setTimeout()とsetInterval()

setTimeout()とは?

setTimeout(FUNC,N)は実行キュー終了後にNミリ秒待ってFUNCを実行するように登録する関数。

 (function () {
   console.log(1);
   setTimeout(function(){
     console.log('X');
   }, 3000);
   console.log(2);
   return;
   console.log(3)
 })()
 console.log(4)
 1
 2
 4
 (3000ミリ秒待ってから)
 X

"1"→"X"→"2"→"4"とはならない。

タイマーで呼ばれるコールバック関数はグローバルスコープで実行される

 var Foo = function () {
   this.num = 999;
   this.showNum = function () {
     alert(this.num);
   }
   this.showNumLater = function () {
     setTimeout(this.showNum, 1000);
   }
 };
 
 var foo = new Foo;
 foo.showNum();      // => 999
 foo.showNumLater(); // => Undefined

showNumLater()から呼ばれるコールバック関数であるshowNum()はグローバルスコープで実行される。よって、this.numはグローバルオブジェクトを指す。this.numはFoo.numではない。

すべてのタイマーをクリアする

 for(var i = 1; i < 1000; i++) {
     clearTimeout(i);
 }

この方法でもタイマーIDに漏れがある事もあるらしい。

タイマーで呼ばれるコールバック関数が引数を受け取る場合、無名関数でラップする

 function foo(a,b) { console.log(a + "," + b); }
  
 setTimeout("foo(1,2)", 500);            
 setTimeout(function(){ foo(1,2) }, 500);

前者のように"foo(1,2)"のような文字列を渡してeval()する事も出来るが、後者のように無名関数を使う方がベタープラクティス。

以下の例ではグローバルのfoo()が呼ばれる。

 function foo() { console.log("1"); }
 function bar() { 
   function foo() { console.log("2"); }; 
   setTimeout("foo()", 500);
 } 
 bar(); // => "1

コールバック関数へ引数を渡す

 function foo(n) { console.log("DEBUG: " + n); }
  
 setTimeout("foo(100)", 0);
 var num = 200;
 setTimeout("foo(" + num + ")", 0); 

↑のように引数を含めて文字列で渡してevalする事も出来なくはないが、↓のように無名関数をでラップした方が良い。

コールバック関数へ引数を渡す方法

 function foo(n) { console.log("DEBUG: " + n); }
 var num = 100;
 setTimeout(function () { foo(num) }, 0);

あるいは、

 var num = 100;
 setTimeout((function(n){
   return function(){ console.log(n); };
 })(num), 0);

即時関数への引数で渡し、それをコールバック関数内で参照する。

引数の内容が確定するタイミング

↑の方法では、

 function foo(n) { console.log("DEBUG: " + n); }
 var num = 100;
 setTimeout(function () { foo(num) }, 0);
 num = 200;
 DEBUG: 200

setTimeout()実行後にnumを100から200へ変えると、コールバック関数実行時に渡される引数は200を参照する。100を参照するようにするには↓のようにする。

 function foo(n) { console.log("DEBUG: " + n); }
 var num = 100;
 setTimeout((function(n){
   return foo(n);
 })(num), 0);
 num = 200;
 DEBUG: 100

詳しくやると↓。

 var num = 100;
 (function () {
   console.log("INSIDE1: " + num);
   setTimeout((function(n){
     return function(){
     console.log("CALLBACK: " + n);
     console.log("CALLBACK: " + this.num);
   };})(num), 0);
   num = 200;
   console.log("INSIDE2: " + num);
 })()
 console.log("OUTSIDE: " + num);
 INSIDE1:  100
 INSIDE2:  200
 OUTSIDE:  200
 CALLBACK: 100
 CALLBACK: 200

コールバック関数に渡される引数nの値はsetTimeout()実行時に決まる。グローバルのnumは100から200へ変わった後の値を参照している。


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS