

タイマーをjsで作る際に下記のように再帰呼び出しで作ることがよくあると思います。  
この処理がうまくいくことが疑問です。

[code]

    function timers(){
         timerId = setTimeout(function() {
              //処理
             timers();
         }, 10);
    }
    
    function stoptimers() {
         clearTimeout(timerId);
    }
    
[/code]

変数timerIdに入ったタイマーIDを引数にclearTimeoutをしているのでタイマーが止まる仕組みなのはわかるのですが、再帰呼び出しで無限ループしていると＝の右の処理が終了していないので代入は行われないのではないでしょうか？どのタイミングで変数timerIdに値が入っているのか不明です。

ご存知の方教えてください。


CC BY-SA 3.0
2015-09-02T00:16:37.023
15127
2015-09-02T16:08:25.863
2015-09-02T00:41:42.163
5044
8823
question
javascript
js timer処理の再帰呼び出しループの疑問


代入の時点では再帰呼び出し（？）は起こっていなくて、単に関数式として保持されるだけ（指定時間経過後に呼び出されて実行される）なので、呼び出す処理が終わっていなくても代入を完了できます。

* * *

関数式は引数として渡された時に実行されてその結果に置き換えられるのではなくて単に関数オブジェクトなので、これを再帰呼び出しというかは疑問に思います。  
おそらくは、キューのようなものに  
[`function() {timers(); }`,`function() {別の関数とか(); }`,`function() {timers();
}/*※同時には積まれない。次の(つまり未来の)やつのつもり*/`,...]//キューのつもり  
のように並びで格納されて先から呼び出されて消費される。  
というようなイメージで実行されるかと思います。


CC BY-SA 3.0
2015-09-02T00:36:03.837
15128
2015-09-02T01:01:47.960
2015-09-02T01:01:47.960
5044
5044
15127
answer


一番分かりやすいのは、ブラウザで実際にsetTimeout関数を実行してみることです。Google
Chromeのコンソールなどで以下のコードを実行してみてください。

[code]

    setTimeout(function() { console.debug('done'); }, 1000)
    
[/code]

実行直後に表示される数値がsetTimeout関数の戻り値であるtimeoutIDです。その１秒後に、コンソール上に「done」と表示されるはずです。

javascriptの関数は第１級オブジェクトと呼ばれ、変数に代入したり、関数の引数や戻り値にしたりできます。setTimeout関数の第１引数は関数です。例のソースでは、その場で無名関数を定義をし引数として渡しているので、慣れないうちはややこしく感じるかもしれません。

以下のソースを見れば理解しやすいかと思います。（処理としては等価です）

[code]

    function timers() {
        timerId = setTimeout(next, 10);
        // ↑ next関数を呼び出しているのではなく、関数定義を渡している
        // next関数を呼び出したい場合はnext()のように括弧が必要
    }
    
    function next() {
        console.debug('next');
        timers();
    }
    ....
    
[/code]


CC BY-SA 3.0
2015-09-02T15:57:53.770
15154
2015-09-02T16:08:25.863
2015-09-02T16:08:25.863
9608
9608
15127
answer