setInterval/setTimeout を使った非同期ループ

December 10, 2007category: JavaScript 

以下のような巨大なループを実行するとブラウザがフリーズする。

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 ループを非同期ループに置き換えることができない。
  • 同様に、ネストすることが難しい。

comments (0)このエントリーを含むはてなブックマークはてなブックマーク - setInterval/setTimeout を使った非同期ループ

comments