概要
Promiseについての説明は調べれば色々と記事があるので割愛します。
ここではこう書いたらこう動くみたいなサンプルをまとめます。(自分が忘れないようのメモとして。。)
今回は5つの処理を行う場合を例として上げてみます。
実行環境
Node.js | v6.10.0 |
---|
サンプル
ダメな例
一部このような書き方が紹介されているような記事があったので念のため書いて置きます。
function task1() {
setTimeout(function() {
console.log('task1');
}, 300);
}
function task2() {
setTimeout(function() {
console.log('task2');
}, 200);
}
function task3() {
setTimeout(function() {
console.log('task3');
}, 100);
}
function task4() {
setTimeout(function() {
console.log('task4');
}, 500);
}
function task5() {
setTimeout(function() {
console.log('task5');
}, 400);
}
Promise.resolve()
.then(task1)
.then(task2)
.then(task3)
.then(task4)
.then(task5);
task3
task2
task1
task5
task4
これだと思った通りの順番にはなりません。
この書き方だとtask1から順番に実行してほしいような書き方に見えますが、
実際には並列で全て実行されるのと同じになります。
ちゃんとPromiseを返すような関数にする必要があります。
全て直列
先ほどと違って各関数内でreturnでPromiseを返すようにします。
function task1() {
return new Promise(function (resolve, reject) {
setTimeout(function() {
console.log('task1');
resolve('task1');
}, 300);
});
}
function task2() {
return new Promise(function (resolve, reject) {
setTimeout(function() {
console.log('task2');
resolve('task2');
}, 200);
});
}
function task3() {
return new Promise(function (resolve, reject) {
setTimeout(function() {
console.log('task3');
resolve('task3');
}, 100);
});
}
function task4() {
return new Promise(function (resolve, reject) {
setTimeout(function() {
console.log('task4');
resolve('task4');
}, 500);
});
}
function task5() {
return new Promise(function (resolve, reject) {
setTimeout(function() {
console.log('task5');
resolve('task5');
}, 400);
});
}
Promise.resolve()
.then(task1)
.then(task2)
.then(task3)
.then(task4)
.then(task5);
task1
task2
task3
task4
task5
これで順番通り直列に実行されます。
全て並列
先ほどの5つの処理を全て並列で行うようにします。
Promise.allに各関数を入れた新しい関数を作成します。
function taskAll() {
return Promise.all([task1(),
task2(),
task3(),
task4(),
task5()]);
}
Promise.resolve()
.then(taskAll);
task3
task2
task1
task5
task4
このように並列に実行されます。
もしくはtaskAll関数を作らず、単純にこれでも並列処理できます。
Promise.all([task1(),
task2(),
task3(),
task4(),
task5()]);
task3
task2
task1
task5
task4
直列と並列の組み合わせ(その1)
task1を実行して、その後task2,3,4を並列に実行、それらが終わったら最後にtask5を実行する
ような処理を考えてみます。
先ほどの並列実行と同じように並列に処理したい関数をまとめてPromise.allに書きます。
function task234() {
return Promise.all([task2(),
task3(),
task4()]);
}
するとこの部分は並列処理になるので、残りを直列に実行します。
Promise.resolve()
.then(task1)
.then(task234)
.then(task5);
task1
task3
task2
task4
task5
task1が最初に実行され、task2,3,4が並列になり最後にtask5が実行されています。
直列と並列の組み合わせ(その2)
先ほどの直列と並列の組み合わせと同じですが、
task2,3,4を実行した結果をtask5で使う場合のサンプルです。
Promise.allは成功すると全ての結果が配列で返ってきます。
(並列処理のどれか一つでも失敗すると全体も失敗に流れます。)
task5の関数でPromise.allの結果を受け取るように修正します。
function task5(result) {
return new Promise(function (resolve, reject) {
setTimeout(function() {
console.log('task5');
console.log(result);
resolve('task5');
}, 400);
});
}
task1
task3
task2
task4
task5
[ 'task2', 'task3', 'task4' ]
まとめ
Promiseを使う場合は今回のように処理を細かく関数に分けてやるのが綺麗な気がします。
処理ごとに細かく分かれていると可読性も良いと思いますし、今回みたいに全て直列、全て並列以外にも
この処理の後にこれを実行する、みたいなことが柔軟に対応できると思います。
慣れてる人は全く気にならないかもですが慣れないと非同期系の処理はコールバックがあったり、思い通りの順番に動いてくれないみたいな事があるので、忘れないようにサンプルとして書き止めておきました。