以下のような巨大なループを実行するとブラウザがフリーズする。
for (var i = 0; i < 100000; i++) { //... } alert("done");
フリーズを回避するには、for ループを、setInterval/setTimeout に置き換えればよい。Flash ならば onEnterFrame イベントも有用。 ここでは、setInterval/setTimeout を使ったループを、非同期ループと呼ぶ。
実装すると以下のようになる。「非同期ループ処理 (7) - 同期非同期複合型」を参考に、幾つかの小さい同期ループに分割した。
非同期ループの実装例
function asynchronousLoop(from, to, obj, func, callback) { var interval = 10; var cellSize = 200; var range = to - from; var innerLoop = function(from, to) { for (var i = from; i < to; i++) { func.apply(obj, [i]); } } if (range < cellSize) { innerLoop(from, to); callback.apply(obj); } else { var cellTotal = Math.ceil(range / cellSize); var count = 0; var intervalId = setInterval(function() { var innerFrom = from + count * cellSize; var innerTo = (from + (count + 1) * cellSize) < to ? (from + (count + 1) * cellSize) : to; innerLoop(innerFrom, innerTo); count++; if (count >= cellTotal) { clearInterval(intervalId); callback.apply(obj); } }, interval); } }
冒頭の 100000 回のループを書き換えるとこうなる。
asynchronousLoop(0, 100000, this, function(i) { //... }, function() { alert("done"); });
非同期ループの問題点
- 別のスレッドになるため、単純に、既存の for ループを非同期ループに置き換えることができない。
- 同様に、ネストすることが難しい。