ひよっこPGのブログ

主に、技術メモや英語たまにギター関連のことも書いているブログです。

setTimeout、setIntervalに指定する関数は出来る限り文字列で渡してはいけない。

○○秒後にある処理を動かしたい場合に使う  setTimeout(関数, ミリ秒数)
○○秒間隔である処理を動かしたい場合に使う setInterval(関数, ミリ秒数)

この二つの引数に ある処理に当たる 動かしたい処理が書かれた関数を指定します。
その指定方法が2つあります。

1. 関数を文字列で渡す。

function test(){
  alert("hoge");
};
// 1秒後にhogeがアラート表示される。
setTimeout("test()", 1000);

2. 関数自体を渡す。

function test(){
  alert("hoge");
};
// 1秒後にhogeがアラート表示される。
setTimeout(test, 1000);

1. 関数を文字列で渡す。の場合は、内部的にeval関数を呼び出して処理しているみたいでこれが注意すべき点です。
eval関数は 文字列をJavaScriptコンパイラに渡して、実行する関数です。渡された小さな文字列を実行するたびにコンパイラを走らせる必要があるため、その結果実行速度が遅くなります

2. 関数自体を渡す。の場合は通常どおり、関数を呼び出しているだけだと思います。

実行速度の比較を行ってみたので参考に^ー^

比較方法は、カウント処理1000回の実行時間で比較します。

var StopWatch = function(){
  this.startTime;
  this.stopTime;
  this.elapsedTime;
  
  /**
   * スタート時間記録
   */
  this.start = function(){
    this.startTime = new Date();
  }
  /**
   * ストップ時間記録
   */
  this.stop = function(){
    this.stopTime = new Date();
    this.elapsedTime = this.stopTime - this.startTime;
    return this.elapsedTime;
  }
};
var sw = new StopWatch();
var count = 0;
function countFunc(){
	count++;
	if(count % 1000 === 0){
		alert("実行速度 : "+sw.stop()+"msec");
	}
};

// test1とtest2、コメントを入れ替えれると比較出来ます。

function test1(){ // 1.関数を文字列で渡す
	for(var i=0; i<1000; i++){
		setTimeout("countFunc()",0);
	}
};
sw.start();
test1();

// function test2(){ // 2. 関数自体を渡す。
// 	for(var i=0; i<1000; i++){
// 		setTimeout(countFunc,0);
// 	}
// };
// sw.start();
// test2();

f:id:buzzword111:20140115123903p:plain
f:id:buzzword111:20140115123912p:plain

1000回実行すると、0.6秒ほど差がでています。
数回の実行であればそこまで差は出ないですが、なるべくなら関数を文字列で渡さない方がいいですね。


ここで自分は一考したのですが、この1. 関数を文字列で使うパターンを使用した場合って
処理したい関数に引数を渡したい場合が多いんじゃないかなと。

下記のような理由だからです。

1. 関数を文字列で渡す 処理したい関数に引数を渡せる
2. 関数自体を渡す 処理したい関数に引数を渡せない。

引数を渡して処理したい場合は、1. 関数を文字列で渡す方法しかないと言われればそうではないみたいです。

参考 : 引数有りのsetTimeout()について MAxUraの落書き帳 ~Scrawl Note~
上記サイトでは、処理したい関数を 無名関数で囲むことによって引数を渡してますね。
無名自体に引数を持っていないので、setTimeoutに渡すことが出来る。
その中で引数を持った処理をすれば大丈夫では? という考えで解決してます。


これらのことから、自分は引数を渡したい場合は 無名関数を渡してその無名関数内で引数を使った処理を書くという方法がよさげだと思います。


まとめ

setTimeoutやsetIntervalに渡す関数は、文字列ではなるべく渡さない。

// ×××
function test(){};
setTimeout("test()", 1000);

// ○○○
function test(){};
setTimeout(test, 1000);

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス