JavaScriptで常に頭を悩ませるのが非同期処理ではないかと思います。非同期処理を幾つも実行したりすると、思ったタイミングで処理が走らないといったことが多々あります。
そんな中でループ処理になると、特に厄介ではないでしょうか。そこで今回はPromiseを使ったループ処理について紹介します。
0から10まで順番に処理をしたら抜けるループ
非同期処理でない場合は次のように書けます。
for (var i = 0; i <= 10; i++) {
console.log(i)
}
console.log(“Finish”);
厄介なのは非同期処理時です。まず、基本形として次のようにPromiseを考えます。
new Promise(function(res, rej) {
}).then(function() {
console.log(“Finish”);
})
この処理は一瞬で終了してしまいます。コンソールにも特に何もメッセージは出ません。この中でループ処理を行うようにします。この時、注意するのは非同期処理がターゲットと言うことです。そのため、loop関数の中でもPromiseを使って処理を行うようにして、処理順番を保証します。
new Promise(function(res, rej) {
function loop(i) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(i);
resolve(i+1);
}, 100);
})
}
loop(0);
}).then(function() {
console.log(“Finish”);
})
これにより、非同期処理(setTimeout)が実行された後、resolveが実行されるようになります。後は内側のPromiseについて、then処理を書きます。
// ループ処理の完了を受け取るPromise
new Promise(function(res, rej) {
// ループ処理(再帰的に呼び出し)
function loop(i) {
// 非同期処理なのでPromiseを利用
return new Promise(function(resolve, reject) {
// 非同期処理部分
setTimeout(function() {
console.log(i);
// resolveを呼び出し
resolve(i+1);
}, 100);
})
.then(function(count) {
// ループを抜けるかどうかの判定
if (count > 10) {
// 抜ける(外側のPromiseのresolve判定を実行)
res();
} else {
// 再帰的に実行
loop(count);
}
});
}
// 初回実行
loop(0);
}).then(function() {
// ループ処理が終わったらここにくる
console.log(“Finish”);
})
thenの中で処理判定を行い、ループを抜けるかどうかの判定を行っています。これで非同期処理における処理順番の保証と、処理完了時に次の処理につながる部分ができました。
JavaScriptにおける非同期処理のループはかなり面倒であるというのが分かるかと思います。JSDoc: Namespace: asyncを使うと非同期処理におけるループがこれくらい分かりやすく書けるようになります。以下は処理を5回繰り返すという指定です。
var loop = h5.async.loop(new Array(5), function (i, v) {
var deffered = h5.async.deferred();
var loop = function (count) {
setTimeout(function () {
console.log(count);
deffered.resolve(count);
}, 100);
};
loop(i);
return deffered.promise();
}).done(function () {
console.log(“処理完了”);
});
コメントは受け付けていません。