- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- JavaScript/タイマー処理/コールバック関数が実行されるタイミング へ行く。
- 1 (2011-07-24 (日) 16:18:37)
- 2 (2011-07-24 (日) 17:29:28)
- 3 (2012-01-27 (金) 21:04:33)
- 4 (2012-01-28 (土) 14:21:40)
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へ変わった後の値を参照している。