LoginSignup
4
0

More than 3 years have passed since last update.

【JavaScript】Promiseをしっかり理解したい【その2】

Last updated at Posted at 2020-07-08

初めに

前回に引き続きPromiseの学習を行います。
【JavaScript】Promiseをしっかり理解したい【その1】

Promiseの書き方

前回も軽く触れましたがPromiseを使った非同期処理の書き方について見ていきましょう。

Promiseによる非同期処理の書き方
function asyncFunc(data) { // ①非同期処理を関数としてまとめる
  return new Promise((resolve, reject) => { // ②Promiseをインスタンス化し戻り値に設定
    setTimeout(() => {
      console.log('--処理実行--');
      if (data) {
        resolve(data * 2); // ③処理の成功時にresolveを呼び出す
      } else {
        reject('未入力です'); // ④処理の失敗時にrejectを呼び出す
      }
    }, 3000);
  });
}

asyncFunc(2) // ⑤非同期関数の呼び出し
   .then((result) => { // ⑥Promiseオブジェクトでresolveされた場合thenメソッドへ処理が移る
     console.log(result);
   })
   .catch((error) => { // ⑦Promiseオブジェクトでrejectされた場合catchメソッドへ処理が移る
     console.log(error);
   });
実行結果
--処理実行--
4

もちろん他にも書き方はありますが、上記の例が個人的に簡潔でわかりやすいかなと思います。中身を見ていきましょう。①非同期処理をasyncFuncのように関数としてまとめます。②その関数では、Promiseオブジェクトが戻り値として返されるように記述します。⑤まとめた関数を呼び出し、③Promise内でresolveされた場合、⑥Promiseのインスタンスメソッドであるthenに処理が移ります。thenメソッドでは主に非同期処理が完了した後に実行したい処理を記述します。また、④Promise内でrejectされた場合、⑦同じくPromiseのインスタンスメソッドであるcatchに処理が移ります。rejectしてあげることでエラーハンドリングをすることができます。

Promiseを使用しなかった場合

もし、上記の例でPromiseを使用しなかった場合はどうなるでしょうか。

Promiseを使用しなかった場合
function asyncFunc(data) {
  setTimeout(() => {
    console.log('--処理実行--');
    if (data) {
      return data * 2;
    } else {
      return '未入力です';
    }
  }, 3000);
}

const result = asyncFunc(2);
console.log(result);
実行結果
undefined
--処理実行--

Promiseを使用しなかった場合、setTimeout関数内の処理が始まる前に最後の行のconsole.logが呼び出されてしまっていることがわかります。

thenメソッド

thenはPromiseのインスタンスメソッドです。

thenの構文
const p = new Promise(...);
p.then(onFulfilled, onRejected);

onFulfilled

Promiseオブジェクト内でresolveした時、onFulfilledが呼ばれます。

onRejected

Promiseオブジェクト内でrejectした時、onRejectedが呼ばれます。

onFulfilledonRejectedはどちらもオプショナル(任意)な引数なので、設定しなくても構いません。
thenメソッドでonRejectedが扱えるということは、thenメソッドだけで成功時と失敗時の両方の処理が書けるということになります。
今までの例でエラー処理はcatchメソッドを使用していましたが以下のようにthenメソッドで一纏めにすることも可能です。

thenメソッド内でエラー処理も行う場合
function asyncFunc(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('--処理実行--');
      if (data) {
        resolve(data * 2);
      } else {
        reject('未入力です');
      }
    }, 3000);
  });
}

asyncFunc() // 引数なし
   .then(
      (result) => { // ①onFulfilled
        console.log(result);
      }, 
      (error) => { // ②onRejected
        console.log(error);
      }
   );
実行結果
--処理実行--
未入力です

上記の例では、resolveされた場合は①のonFulfilledが呼ばれ、rejectされた場合は②のonRejectedが呼ばれます。asyncFunc関数の呼び出し時に引数を渡していないので、Promiseオブジェクト内でrejectされ、実行結果からもonRejectedが呼び出されていることがわかります。

catchメソッド

catchもthenと同様にPromiseのインスタンスメソッドです。

catchの構文
const p = new Promise(...);
p.catch(onRejected);

catchメソッドの場合はonRejectedしかありません。
今までの例でもエラー処理はcatchメソッドを使用してきました。個人的にthenメソッドでonFulfilledonRejectedの両方を書くよりも、catchメソッドを使って処理を別々に分けたほうがわかりやすいかと思っています。

Promiseの状態

Promiseオブジェクトには3つの状態というものがあります。

Fulfilled

Promiseオブジェクト内でresolve(成功)した時。このときonFulfilledが呼ばれます。

Rejected

Promiseオブジェクト内でreject(失敗)した時。このときonRejectedが呼ばれます。

Pending

FulfilledまたはRejectedではない時。Promiseオブジェクトが作成された初期状態や処理の実行中がこの状態に当てはまります。

Promiseオブジェクトの状態は、一度PendingからFulfilledRejectedに移ると、そのPromiseオブジェクトの状態はそれ以降変化しません。なので、then等に書いた処理が実行されるのは一度きりになります。
また、このことからFulfilledRejectedのどちらかの状態であることを、「確立した、不変な」を意味するSettledと表現することがあるそうです。

Settled

Promiseオブジェクト内でresolve(成功) または reject(失敗) した時。つまりFulfilledRejectedの状態である時。

Promiseを抽象化するとPending(未決)からSettled(解決)の状態変化である、と言えるでしょう。Promiseの状態については実装等で直接使用することはありませんが、Promiseの理解の為に頭の片隅に入れておくと良いかと思われます。

まとめ

実際に実装する分には、今回のPromiseの書き方だけ押さえておけば問題ないかと思います。ただ、根本的な理解だとまだまだ足りないことが多いと感じているので引き続き学習していきたいと思います。

次回

【JavaScript】Promiseをしっかり理解したい【その3】

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0