JavaScript while
ステートメント(Chromeのコンソール内)が1ミリ秒で変数をインクリメントできるのは何回か疑問に思ったので、このスニペットをコンソールに直接書き込みました。
var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }
問題は、それが永久に実行されることです。
なぜこれが起こっているのですか、どうすれば解決できますか?
これは、JavaScriptのワンスレッドの性質に戻ります1。何が起こるかはほとんどこれです:
run = false
_を設定します。これは実行されるようにスケジュールされていますafter現在の関数が実行されます(または他の現在アクティブなものは何でも)。setTimeout()
コールバックが実行され、_run=false
_が実行されます。ご覧のとおり、ここではsetTimeout()
アプローチは機能しません。 while
条件で時間をチェックすることでこれを回避できますが、これは実際の測定値を改ざんします。
1 少なくともより実用的な目的では、シングルスレッドとして見ることができます。実際には、いわゆる「イベントループ」があります。そのループでは、すべての関数が実行されるまでキューに入れられます。新しい関数をキューに入れると、そのキュー内のそれぞれの位置に配置されます。 現在の関数が終了した後、エンジンはキューから次の関数を取得します(たとえば、setTimeout()
によって導入されたタイミングに関して、それを実行します。
その結果、すべての時点で1つの関数のみが実行されるため、実行はほぼシングルスレッドになります。以下のリンクで説明されているイベントにはいくつかの例外があります。
参考のために:
https://stackoverflow.com/a/16757582/1169798
ここでは、同様のシナリオがより詳細に説明されています
https://stackoverflow.com/a/2734311/1169798
JSがシングルスレッドと見なされる場合とそうでない場合についてのより詳細な説明。
JavaScriptはシングルスレッドであるため、ループ内にいる間は他に何も実行されません。
速度を計算する時間を絶えず取得することなく、Chromeの真の速度を維持するには、次のJSコードを試すことができます。
var start = new Date().getTime()
var i = 0
while(i<1000000)
{
i++
}
var end = new Date().getTime()
var delta = end-start
var speed = i/delta
console.log(speed + " loops per millisecond")
Javascriptはシングルスレッドです。つまり、一度に1つの命令のみを順番に実行します。
イベントシステムは、他の多くの言語やライブラリと同様に、イベントループによって処理されます。イベントループは基本的にループであり、反復ごとにキュー内のメッセージをチェックし、イベントをディスパッチします。
Javascriptでは(このパターンを実装する言語のmotのように)、スタックが空のとき、つまり、すべての関数がプログラムコードの最後に戻り値を持っているときに、イベントループが呼び出されます。
あなたの「本当の」プログラムは舞台裏で次のように見えます:
var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }
while(true) {
/*
* check for new messages in the queue and dispatch
* events if there are some
*/
processEvents();
}
したがって、タイムアウトが終了したことを示す時計からのメッセージは処理されません。
イベントループの詳細: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop
もちろん、もう少し複雑です。ここでそれらの例を確認してください: JavaScriptはシングルスレッドであることが保証されていますか? (tl; dr:一部のブラウザエンジンでは、一部の外部イベントはイベントループに依存せず、発生するとすぐに発生し、現在のタスクをプリエンプトします。ただし、これはsetTimeoutの場合ではなく、キューにメッセージを追加するだけで、決してすぐに発砲します。)
WhileループはsetTimeoutにアクセスしません。セットがtrueで実行されるコードがあり、それがfalseになることはありません。
JavaScriptにはシングルスレッドがあり、どこにでもシングルスレッドがあります。
この質問は良いと思います: JavaScriptはシングルスレッドであることが保証されていますか?
コードがループ内にある場合、他のocdeは実行およびブロックされません。