2013年7月28日日曜日

[JavaScript]ライブラリを使わない非同期ループ

jQueryなどのライブラリに依存しないでお手軽に非同期ループを実現する方法。
これは結構使えるのでメモ。

/**
 * 非同期ループ
 * 
 * array
 * fn
 * onprogress
 * onend
 */
function asyncEach(array, fn, progress, onend) {
  var i = 0,
  maxBurnTime = 100, // ms to run before yielding to user agent
  onendFn = onend || progress,
  progressFn = (onendFn === progress ? null : progress);

  function iter() {
    var startTime = Date.now();

    while(i < array.length) {
      fn.call(array, array[i], i++);

      if(Date.now() - startTime > maxBurnTime) {
        if(progressFn) progressFn(i, array.length);
        return window.setTimeout(iter, 0);
      }
    }

    if(progressFn) progressFn(i, array.length);
    if(onendFn) onendFn(null, array);
  }
  window.setTimeout(iter, 0);
}

//
// テスト実行
//
var arr = [ 'one', 'two', 'three' ];

asyncEach(arr,
  // function
  function(item, i){
   console.log('start' + i);
    // ランダムにスリープ後、ログ出力
    setTimeout(function(){
      console.log('item' + i + '=' + item);
    }, Math.floor(Math.random() * 100));
  },
  // onprogress
  function(loaded, total){
    console.log(loaded + '/' + total);
  },
  // onend
  function(err, val){
    console.log('val=' + val + ', err=' + err);
  });

これを実行すると、

start0
start1
start2
3/3
val=one,two,three, err=null
item1=two
item0=one
item2=three

こんなふうにログ出力されます。
第二引数の関数が非同期的に実行されているのが分かりますね。

参考にさせてもらったサイト。
async forEach in JavaScript

0 件のコメント:

コメントを投稿