はじめに
JavaScriptでPromiseを使い始めたとき、出来ると便利な以下の場合について。
- Promiseで順番に実行する直列処理を、ループで繰り返す。
- ループ完了後に実行したい処理がある。
Promiseをループで繰り返す
まず最初に、Promiseの処理をforループで繰り返す基本パターン。
// Promiseの処理をループで繰り返す
var myPromise = Promise.resolve();
for(var i = 0; i < 3; i++) {
myPromise = myPromise
.then(task1.bind(this, i)) // bindでtask1に引数iを渡す
}
// ループで実行する処理
function task1(val){ // 引数iを受け取る
return new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('task1 : ' + val);
resolve();
}, 1000);
});
}
実行結果
task1 : 0
task1 : 1
task1 : 2
実行パターン
直列処理を繰り返す
メソッドチェーンでつないだ、Promiseの直列処理をループで繰り返すパターン。
// Promiseの直列処理をループで繰り返す
var myPromise = Promise.resolve();
for(var i = 0; i < 3; i++) {
myPromise = myPromise
.then(task1.bind(this, i)) // bindでtask1に引数iを渡す
.then(task2)
}
// ループで実行する処理
function task1(val){ // 引数iを受け取る
return new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('task1 : ' + val);
resolve(val); // task2へ値を渡す
}, 1000);
});
}
function task2(res){ // task1から値を受け取る
return new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('task2 : ' + res);
resolve();
}, 1000);
});
}
実行結果
task1 : 0
task2 : 0
task1 : 1
task2 : 1
task1 : 2
task2 : 2
ループ完了後に実行
メソッドチェーンでつないだ、Promiseの直列処理をループで繰り返し、ループ完了後に処理を実行する。
// Promiseの直列処理をループで繰り返す
var myPromise = Promise.resolve();
for(var i = 0; i < 3; i++) {
myPromise = myPromise
.then(task1.bind(this, i)) // bindでtask1に引数iを渡す
.then(task2)
}
myPromise
.then(function(){
return new Promise(function (resolve, reject) {
// ループ完了後に実行したい処理
console.log('ループ完了後に実行');
resolve();
});
})
// ループで実行する処理
function task1(val){ // 引数iを受け取る
return new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('task1 : ' + val);
resolve(val); // task2へ値を渡す
}, 1000);
});
}
function task2(res){ // task1から値を受け取る
return new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('task2 : ' + res);
resolve();
}, 1000);
});
}
実行結果
task1 : 0
task2 : 0
task1 : 1
task2 : 1
task1 : 2
task2 : 2
ループ完了後に実行
ループで繰り返す処理をまとめる
ループで繰り返す直列処理task1()
とtask2()
をtaskAll()
にまとめたパターン。
実行結果は同じです。
// Promiseの直列処理をループで繰り返す
var myPromise = Promise.resolve();
for(var i = 0; i < 3; i++) {
taskAll(i);
}
myPromise
.then(function(){
return new Promise(function (resolve, reject) {
// ループ完了後に実行したい処理
console.log('ループ完了後に実行');
resolve();
});
})
// ループで実行する処理
function taskAll(i){
myPromise = myPromise
.then(task1.bind(this, i)) // bindでtask1に引数iを渡す
.then(task2)
}
function task1(val){ // 引数iを受け取る
return new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('task1 : ' + val);
resolve(val); // task2へ値を渡す
}, 1000);
});
}
function task2(res){ // task1から値を受け取る
return new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('task2 : ' + res);
resolve();
}, 1000);
});
}
実行結果
task1 : 0
task2 : 0
task1 : 1
task2 : 1
task1 : 2
task2 : 2
ループ完了後に実行
taskAll()
に直列処理だけではなく、Promise.all()
で並列処理を組み合わせることも出来ます。
おわりに
他にも使いそうな便利なパターンがあれば追記します。
※ 直列処理や引数の扱いについては、Promiseとthenのメソッドチェーン(直列・並列・値の受け取り・引数)を参照。