8) 逐次処理
taskA()
taskB()
taskC()
の順に処理を呼び出したい場合はどのように呼び出せば良いのでしょうか。
thenのメソッドチェインを使う
then()
のメソッドチェインを使うと、Promiseオブジェクトの結果を次のthen()
に渡す事ができます。つまりPromiseオブジェクトが fulfilled になるのを待ってから次のPromiseオブジェクトを実行する事ができます。
taskA()
.then(taskB)
.then(taskC)
;
// A called
// A fulfilled
// B called
// B fulfilled
// C called
// C fulfilled
しかしこのパターンはあまり好まれません。長すぎるthen()
のメソッドチェインは処理を分かりづらくさせるとされています。
reduce
逐次処理をシンプルに書く方法としてよく見るのがArray.reduce()
を使った方法です。
[taskA,taskB,taskC].reduce(function(promise, task){
return promise.then(task);
}, Promise.resolve());
// A called
// A fulfilled
// B called
// B fulfilled
// C called
// C fulfilled
reduce()
は、「配列内の隣り合う2つの要素をコールバック関数の処理によって単一の値に変換する 」という処理を要素数分だけ繰り返すことで、最終的に単一の値を出力するメソッドです。(参考)
reduce()
の第二引数に渡したPromise.resolve()
とtaskA
の組から始まり、その結果とtaskB
、その結果とtaskC
、という順にコールバック関数が適用されていきます。
擬似的なコードで表現すると、以下のような動作になります。
1回目
function({Promise.resolve()},taskA){
return {Promise.resolve()}.then(taskA);
}
2回目
function({1回目の結果},taskB){
return {1回目の結果}.then(taskB);
}
3回目
function({2回目の結果},taskC){
return {2回目の結果}.then(taskC);
}
つまり、この方法でthen()
のメソッドチェインと同じ処理が表現できているというわけです。
Promise.resolve()
.then(taskA)
.then(taskB)
.then(taskC)
;
メソッドチェインと同じため rejected な状態をcatch()
で拾う事も可能です。
var tasks = [taskA,taskB,taskC].reduce(function(promise, task){
return promise.then(task);
}, Promise.resolve());
tasks.catch(function(error){
console.error(error.message);
});