javascript で wait処理

Javascriptではwait処理はない。
でも、ある処理Aが完了した後に、処理Bをして欲しい場合が往々にしてある。


例えば、以下のような処理。

  var a = func1();
  func2(a);


通常の場合だと、この処理はfunc1 → func2と処理される。


だけどfunc1の中で、setTimeoutやsetIntervalが利用されてると、
うまくいかないケースがある。


例えば、以下のケースを実行すると

var a = 0;
function func1(){
 if( a < 10){
    a++;
    alert("hoge" + a);
    setTimeout("func1()", 500);
  }
  else{
    alert("END");
    return a
  }
}
function func2(val){
  alert ("call func2: " + val);
}

var value = func1();
func2(value);

実行結果は

hoge1
call func2: undefined    ← ココですでに呼ばれてしまっている!!
hoge2
hoge3
hoge4
hoge5
hoge6
hoge7
hoge8
hoge9
hoge10
END

となる。


つまり、func1 → func2 → func1 → func1.... となる 。


この辺についてはid:amachangのこの記事が参考になります。(JavaScript を学ぶ際に一番重要なのに、誤解されがちな setTimeout 系の概念)


なんとかwaitみたいな処理が出来ないか考えて見ました。

webをクロールすると2種類の方法が在るようです。

  1. for か while でグルグル回す。
  2. setTimeout か setIntervalを利用する。

1はあり得ないですよね。
というわけで、2の方法で模索してみました。
軽くweb上をググってみるとこのような記事が目につきますが


ぶっちゃけ、ややこしすぎてわからんw。
いや、わかるんやけど、汎用的にしようとして余計なコードが多すぎる(と私は思いますと言ってみるテスト)


なので、やっぱり自分で作ってみました。
こんな感じのコードで至ってシンプル。

timerID = setInterval(function(){
                         if(waitの終了条件){
                         wait終了時の後処理
                         clearInterval(timerID);
                         timerID = null;
                         }
                      }, 20);  // polling time  = 20ms

で出来ました。


先ほどの例を作った形に当てはめると。

var a = 0;
function func1(){
 if( a < 10){
    a++;
    alert("hoge" +a);
  }
  else{
    alert("END");
    return a
  }
}
function func2(val){
  alert ("call func2: " + val);
}

timerID = setInterval( function(){
                         value = func1();
                         if(value == 10){
                           func2(value);
                           clearInterval(timerID);
                           timerID = null;
                          }
                        },1000);

んで、実行結果は

hoge1
hoge2
hoge3
hoge4
hoge5
hoge6
hoge7
hoge8
hoge9
hoge10
END
call func2: 10


わーーーー、わーーーーー、パチパチパチ!!!


気をつけなきゃいけない箇所はwait終了条件
このサンプルプログラムを作るときに間違えてif(value < 10 )と間違えてはまったのは内緒の話だ。

このwait処理の実行条件としては、setInterval内で利用する変数(例えばループ終了条件)については、
setIntervalの外で宣言しないとだめな点かもしれない。

追伸

試してないけど、このコードってこうしたら汎用的につかえね??

/*  引数1: wait終了条件
    引数2: wait終了後のコールバック関数
    引数3: ポーリング時間
    戻り値 正常に終了したかどうか
 */
function wait(flag, fanc, timer){
 var _flag = flag;
 var _func = func;
 var _timer = timer;
 timerID = setInterval(function(){
                         if(eval(_flag)){
                         clearInterval(timerID);
                         timerID = null;
                         _func();
                         }
                      }, _timer); 
}