Chapter 01

Promiseの基本

いーちゃん
いーちゃん
2021.08.15に更新

Promiseは、非同期処理の状態と結果を表現するオブジェクトです。この状態は3種類。

状態 概要
pending 処理が実行中
fulfilled 処理が正常に完了した
rejected 処理が失敗した

また、Promiseオブジェクトは then catch finallyの3つのメソッドをもち、いずれもまたPromiseオブジェクトを返します。これらのメソッドが呼ばれるのは、

メソッド 呼ばれるとき
then Promiseの処理が成功 = fulfilled
catch Promiseの処理が失敗 = rejected
finally Promiseの完了または失敗

のタイミングです。なんとなく try - catch - finallyの構文に似ていますね。
then, catch はそれぞれ成功/失敗した場合に呼び出されるコールバック関数を引数にとり、thenのコールバック関数の引数にPromiseの結果、catchのコールバック関数の引数にはPromiseが失敗した理由(Errorが入ることが多い)が渡されます。

// const promise = Promiseオブジェクト; これ以降のコードでは省略

promise.then(result => { 
  // resultにはPromiseの返り値が代入される
}).catch(reason => {
  // reasonにはPromiseが失敗した理由(Errorほか)が代入される
}).finally(() => {
  // 引数をとらない。fulfilledでもrejectedでも呼び出される
});

Promiseオブジェクトの作り方は主に、

  1. fetchなどの関数の返り値
  2. async functionキーワードを用いた非同期関数
  3. Promiseコンストラクタ new Promise((resolve, reject) => { ... })

があります。基本的には1つ目のように使うことが多く、直接的にPromiseオブジェクトを生成することは少ないと思います。
Promiseコンストラクタは引数に関数を取り、その引数 resolveに値を渡すことでPromiseはfulfilledになり、rejectに値を渡す、もしくはErrorをthrowすることでPromiseはrejectedになるという仕組みです。

new Promise((resolve, reject) => {resolve(引数);
}).then(result => {
  // resultにはresolveの引数が入っている
});

new Promise((resolve, reject) => {reject(引数);
  // もしくは
  throw Errorオブジェクト;
}).catch(reason => {
  // reasonはrejectの引数かthrowされたオブジェクトが入っている
});
then, catch のもう少し細かな仕様

thenメソッドはもうひとつコールバック関数をとることができます。この2つ目のコールバック関数はPromiseが失敗したときに呼び出されます。つまり、catchの内容をthenに書くことができます。実際に、catchメソッドは内部的にthenメソッドを呼び出すとされています。

promise.then(result => { ... }).catch(reason => { ... });
// 上下でやっていることは同じ
promise.then(result => { ... }, reason => { ... });
余談: Promiseはつづくよどこまでも

先述した通り、

Promiseオブジェクトは then catch finallyの3つのメソッドをもち、いずれもまたPromiseオブジェクトを返します
ので、

promise
.then(result => { ... })
.then(result => { ... })
.then(result => { ... })
.then(result => { ... })
.then(result => { ... })
.then(result => { ... })
.then(result => { ... })

と無限につなげることができます。2連続程度はfetchなどで利用例がありますが、ここまで多くつなげる必要もないような...。