2023/09/15 更新
Callbackは嫌だが、Promiseもなかなか馴染めない。async/awiatでいいじゃないか。しかしもう一度だけPromiseを振り返ってみたい。備忘録的なまとめです。
Promise Executor の例外 - Qiita
ES6のPromiseの基本を考えてみた - Qiita
async/awaitのわかりやすい説明です(2019/07/15追加)
async/await 入門(JavaScript)
1.Promise ライフサイクル
Promiseは非同期処理の結果を保持するプレースホルダ(オブジェクト)です。promiseは短いライフサイクルを持ちます。Pending stateでスタートし、Fulfilled state またはRejected state で終了します。
- Pending : promiseの非同期処理はまだ終了していない
- Fulfilled : promiseの非同期処理が終了して、成功した
- Rejected : promiseの非同期処理が終了して、失敗した
2.Promise Executor と Fulfillment handler
Promise Executorについて
Promise Executorとは、Promiseオブジェクトを作成するときに渡すコールバック関数のことです。Promise Executorは、非同期処理の結果をPromiseオブジェクトに反映するための関数です。Promise Executorは、resolve と reject という2つの引数を受け取ります2。resolveは非同期処理が成功したときに呼び出す関数で、引数に非同期処理の結果を渡します。rejectは非同期処理が失敗したときに呼び出す関数で、引数にエラー情報を渡します。Promise Executorは、Promiseオブジェクトの状態をpending(未解決)、fulfilled(解決済み)、rejected(拒否) のいずれかに変更することができます。
Fulfillment handler はthenメッソドの第1引数に渡される関数です。Rejection handler はthenメソッドの第2引数またはcatchメッソドの第1引数に渡される関数です。
以下はPromise Executor と Fulfillment handlerを説明するための短いコードです。
let promise = new Promise(function(resolve, reject) { // (1) Promise Executor
console.log("Promise Executor");
resolve(); // (3) Fulfilled stateになる
});
promise.then(function() { // (2) Fulfillment handler
console.log("Fulfillment handler");
});
console.log("最後の実行");
以下はPromise ExecutorとFulfillment handlerの説明です。
- Promise Executor : Promise()コンストラクタの引数関数(非同期処理)。
- Fulfillment handler : then()の引数関数。
以下はPromise ExecutorとFulfillment handlerの実行タイミングの説明です。
- Promise Executor はすぐに実行されます。 (new Promise(...) call時)
- Promise Executorの中で(3)のresolve()が呼ばれると、(2)のFulfillment handlerがjob queueの最後に追加されます。つまりhandlerは非同期処理になります。
つまりこのコードの実行結果は以下のようになります。Fulfillment handlerが一番最後に実行されます。
Promise Executor
最後の実行
Fulfillment handler
繰り返しになるので省きますが、Fulfilled handlerと全く同じことがRejected handlerについて言えます。
3.promise.then()はpromiseを返す
promise.then()はpromiseを返します。ですからpromise.then().then()...then()のようにチェインで連鎖させることができます。
let p1 = new Promise(function(resolve, reject) {
resolve("スタート");
});
p1.then(function(value) {
console.log(value);
}).then(function() {
console.log("終了");
});
実行結果は以下の通りです。
スタート
終了
4.Fulfilled handler が通常の値をreturnする場合
以下はFulfilled handlerが通常の値をreturnし、次のFulfilled handlerで受け取る例です。
let p1 = new Promise(function(resolve, reject) {
resolve(1);
});
p1.then(function(value) {
console.log(value); // "1"
return value + 1;
}).then(function(value) {
console.log(value); // "2"
});
5.Fulfilled handler が promise をreturnする場合
以下は Fulfilled handlerがpromiseをreturnし、次のFulfilled handlerでそのpromiseのresolve値を受け取る 例です。もしp2がresolve(2)ではなくreject(2)を実行していたら、2番目のFulfillment handlerは呼ばれないことに注意してください。 この場合は、then()でなくcatch()で、Rejected handlerを定義しておけば、それが呼ばれることになります。
let p1 = new Promise(function(resolve, reject) {
resolve(1);
});
let p2 = new Promise(function(resolve, reject) {
resolve(2);
// reject(2)
});
p1.then(function(value) {
// 最初のfulfillment handler
console.log(value); // 1
return p2;
}).then(function(value) {
// 2番目のfulfillment handler
console.log(value); // 2
});
今回は以上です。