アラートの下でプログラムを実行すると、常に「aaa」の後に「bbb」が続く理由を誰かが説明してくれますか? 私はそれが次の手順に従うことを期待します:
プログラムを開始します
プログラムが実行され、setTimeout 行に到達します。タイマーを設定し、このタイマーはこの時点から 5 秒後に起動されます (プログラムの終了時ではありません)。イベントキューにはまだ何も入れられていません
次に、5 秒が経過する前にドキュメントをクリックします。プログラムはビジーでまだループを実行しているため、このクリック イベントのコールバックがイベント キューに置かれます。これは、現時点で偶数キューにある唯一のイベントです (以前に設定されたタイマーはまだ開始されていません)。
5 秒が経過しましたが、ループはおそらくまだ実行中であり、setTimeout で設定したタイマーが起動します。これにより、タイマー コールバック「aaa()」が、実行される 2 番目のイベント コールバックとしてイベント キューに入れられます。これは、既にキューにあるクリック イベントの直後です。
したがって、プログラムが終了すると、このイベントが最初に発生したため(5秒前にクリック)、最初に「bbb」を警告し、次に「aaa」(setTimeoutイベントが発生)が続くと予想されますが、常に「aaa」に続いて「bbb」が発生します"、 何故ですか?
イベントキューがFirst in FIFO(First in first out)になっていませんか? ブラウザ依存ですか?なぜこうなった?
function aaa() {
alert("aaa");
}
setTimeout(aaa, 5000);
document.onclick = function () {
alert("bbb");
}
for (i = 0; i < 1000000; i++) {
console.log(i);
}
JSFiddle はこちらhttp://jsfiddle.net/sQvYG/1/
編集:何かが欠けていない限り(おそらく非常に恥ずかしい)、上記のコードは、 http: //ejohn.org/blog/how-javascript-timers-workで詳細に説明されているJohn Resigsのブログ投稿と非常によく似ているようです/ . まったく同じこと、タイマーが開始され、クリックが発生し、キューに追加されます。タイマーが起動し、キューに追加されます。実行が終了し、クリック ハンドラーが最初に実行されます。なぜこれが私にとって正しい順序で起こっていないのか、誰でも光を当てることができますか?
編集:受け入れられた回答を提供し、キューを詳細に説明してくれたbfavarettoのおかげで、イベントが配置される場所には1つではなく、複数の「タスクキュー」があることがわかりました。上記で最初に説明した 5 つの手順は、実際には次のとおりです。
STEP 1. (こちらも同じ) プログラムを起動します
STEP 2. (これも同じです) プログラムが実行され、setTimeout 行に到達します。タイマーを設定し、このタイマーはこの時点から 5 秒後に起動されます (プログラムの終了時ではありません)。イベントキューにはまだ何も入れられていません。
また、この時点では、mozilla dev ページhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoopで見つけたように、タスク キューにはまだ何も配置されていないと思います。
「setTimeout を呼び出すと、2 番目の引数として渡された時間が経過した後にキューにメッセージが追加されます。」
Chromeでもこれを確認しましたが、実際に起動されたときにコールバックがタスクキューに追加されているようです。
STEP 3. その後、5 秒が経過する前にドキュメントをクリックします。プログラムはビジー状態でまだループを実行しているため、このクリック イベントのコールバックは、ブラウザがこの種のイベント (マウス クリック、UI タスク キュー) に提供するタスク キューの 1 つに置かれます。これは、現時点でこのタスク キュー内の唯一のイベントです。タイムアウトなどの他のタスク キューは、現時点では空です。
ステップ 4. 5 秒が経過しましたが、ループはおそらくまだ実行中であり、設定したタイマーにsetTimeout
火をつけます。これにより、タイマー コールバック「aaa()」が、特にこの種のイベント (タイムアウト) 用にブラウザによって提供されるタスク キューに入れられます。これで、ユーザー インタラクションを処理する 1 つのタスク キューがあり、そこで 1 つのコールバックが待機しています (ポイント 3 で先ほどクリックしたコールバック)。また、タイムアウトを処理する別のタスク キューがあり、そこで待機しているコールバックも 1 つあります。それは、aaa()
5 秒後に発火したばかりのメソッドを持つものです。
ステップ 5. プログラムが終了すると、それぞれ 1 つのコールバックを持つ 2 つのタスク キューが作成されます。クリックが最初にタスク キューに入れられたとしても、このタスク キュー (ユーザー インタラクションまたはマウス クリックを処理するもの) が最初に処理されるという保証はまったくありません。これはブラウザの実装に完全に依存しており、それが bfavaretto が回答で説明するまで頭痛の種でした。
したがって、この例では 2 つのタスク キューについてのみ言及しましたが、ブラウザには他のタスク キューがある可能性があります。プログラムが実行されてビジー状態になると、各タイプのイベントがそのタイプのタスク キューに配置されます。プログラムが終了すると、ブラウザは処理するタスク キューを決定し、そこからコールバックを取得して実行し、終了したら同じまたは別のタスク キューから何かを取得します。したがって、実際には、次にどのキューが処理されるかを知る方法はありません。ただし、特定のキュー内のタスクは常に順番に処理されます。
おっと..これは今では理にかなっているように思えます.Resigの記事は、物事がどのように行われるかについての全体的なアイデアを私に与えてくれました.