8

これは私のテストコードです(ここでフィドル):

console.log('Before wait');
setTimeout(function () { console.log('Yo!'); }, 1000);
var start = Date.now();
while (Date.now() < start + 3000) {}
console.log('After wait');

これは、Chrome でのイベントのタイムラインです。

  • 時間 0 秒: 「待機前」を印刷します。
  • 時間 3 秒: 「待機後」を出力し、「よ!」の直後に出力します。

この動作は仕様どおりですか? なぜそうではないのですか

  • 時間 0 秒: 「待機前」を印刷します。
  • 時間 3 秒: 「待機後」を印刷します。
  • 時間 4 秒: 「よ!」と表示されます。

?

4

4 に答える 4

50

JavaScript はシングルスレッドです。コードの一部のブロックが実行スレッドを使用する場合、他のコードは実行できません。これは、setTimeout()メインの実行 (ビジー待機whileループのあるもの) が終了するまで、呼び出しを待機する必要があることを意味します。

1 秒後に実行するようにスケジュールsetTimeout()し、メイン スレッドを 3 秒間ブロックします。これは、ビジー ループが終了した時点で、タイムアウトがすでに 2 秒遅すぎることを意味します。JS エンジンは、できるだけ早く、つまりすぐにタイムアウトを呼び出すことで、遅れをとらないようにします。

実際、これは:

while (Date.now() < start + 3000) {}

JavaScript で行うには最悪のことの 1 つです。JavaScript 実行スレッドを 3 秒間保持すると、他のイベント/コールバックを実行できなくなります。通常、ブラウザはその期間に「フリーズ」します。

于 2013-02-13T21:03:08.983 に答える
9

の遅延はsetTimeout、それが呼び出された正確な時点に関連しています。あなたがまだ待っている間、それは期限切れになります。そのため、コントロールがイベント ループに戻る次の瞬間に実行されます。

編集:

この時点で仕様は少しあいまいですが、それが意図された唯一の単純な解釈だと思います。

setTimeout(関数、ミリ秒)

このメソッドは、指定されたミリ秒数が経過した後、clearTimeout の呼び出しによってキャンセルされるまで、関数を 1 回呼び出します。メソッドは、その後の clearTimeout の呼び出しで間隔をキャンセルするために使用できる timerID を返します。

于 2013-02-13T21:04:47.690 に答える
2

setTimeout 呼び出しの後にビジー待機ループを実行すると、「ヨ!」の時間がありません。JavaScriptランタイムがループでビジーであるため、印刷します(実際には、ループ条件の評価が継続しているため、空のステートメントもビジーになります)。

このようなビジー待機ループは常に回避する必要があります。これが終了するまで、そのウィンドウで他に何も呼び出したり実行したりできないためです。

于 2013-02-13T21:07:23.007 に答える