Javascriptのシングルスレッドの性質について質問があります。
console.log("1");
setTimeout(function(){console.log("2");},3000);
console.log("3");
setTimeout(function(){console.log("4");},1000);
このコードの結果は1 3 4 2
。ご覧のとおり、4
後に来ます 2
これは、シングルスレッド環境では2
は4
?そうでない場合、JSは2番目のsetTimeout
が最初の1つより前に終了する必要があることをどのようにして知っていますか? setTimeout
に通知するために、2つのEventLoop
sを完了するために同時に動作する2つのスレッドがあるべきではありませんか?
JavaScript(ブラウザ内)しない同時実行2。
最大でoneのsetTimeout
コールバックは一度に実行できます-one JavaScript実行コンテキストまたは「スレッド」があります。
ただし、実行する「次のスケジュールされたタイムアウト」は常に.. nextで実行されます。 「4」は「2」コールバックの前に実行されます。これはより早く実行するようにスケジュールされているであったためです。タイムアウトは効果的にスケジュールされましたfrom同じ時間(どの操作もブロックしていません)でしたが、「2」の間隔はずっと長くなりました。
基礎となる実装mayスレッドを使用1 -ただし、同じグローバルコンテキストのJavaScript does n't同時に実行され、すべてのコールバック間でconsistentおよびatomicの動作を保証します。
1 または、そうでない場合があります。これは、select/poll
実装のスレッドなしで処理できます。
2 同じコンテキスト:タブ/ウィンドウ、WebWorker、ホストブラウザーコントロール。たとえば、WebWorkersは並行して実行されますが、differentコンテキストで実行され、同じ非同期モデル(たとえば、タイマーで使用されるもの)に従います。
Javascriptは、非同期呼び出しにEventloopと呼ばれるものを使用します。 setTimeoutはコールバックであるため、EventLoopにプッシュされます。メインスレッドは引き続き実行されます。メインが完了すると、EventLoopはデータをメインスタックにプッシュします。例:
console.log("1");
setTimeout(function(){console.log("2");},0);
console.log("3");
setTimeout(function(){console.log("4");},1000);
タイムアウトが0の場合、コードの出力は次のようになります。
1 3 2 4
最初にMainの呼び出しを実行してから、Eventloopからデータを返します 同時実行モデルとイベントループ
Javascriptは各行を順番に実行します。
あなたはjsに言った:
js writes 1
ok I'll wait 3 seconds...now what?
ok I'll write 3, by the way, the 3 seconds is not up.
ok I'll wait 1 second...
その後、jsは.99999秒待機し、4を書き込みます
その後、さらに待機して2を書き込みます
setTimeoutの2番目のパラメーターは、コールバック関数(最初の引数)がイベントループにプッシュされる(minimum)時間を取ります。コールバック関数のキュー。このキューは、実際に実行を開始するために消費されます。
最初のsetTimeoutに遭遇すると、関数は外部のどこかにプッシュされ、3秒間待機してからシングルスレッドワールドに再入するように指示されます。 2番目のタイムアウト機能についても同じことが起こりますが、1秒だけ待つ必要があります。このシングルスレッドワールドへのエントリポイントは、コールバックキューです。 JSエンジンは、settimeoutの実行が完了したかのように通常の実行を継続します。 1秒が経過すると、2番目のタイムアウトの機能がキューにプッシュされ、実行を待機します。その時点で呼び出しスタックがクリアされている場合、関数は処理を開始し(キューの最初のメンバーであると仮定)、「4」が出力されます。この時間で3秒が経過していない場合、最初のタイムアウトの機能はまだ外部のどこかで待機しています。 3秒が経過すると、コールバック関数がキューに入り、コールスタックがクリアされているため実行され、「2」が出力されます。
ブラウザは、OSから複数のスレッドにアクセスできるようになりました(ただし、JS実行には単一のスレッド環境のみが提供されます)。これらのsetTimeoutsは、背後で別のスレッドによって処理されます。
フィリップスロバートによるビデオがあり、シングルスレッドjavascriptの「非同期性」につながるキューとイベントループの概念を美しく説明しています。
手順は次のとおりです。
Console.log(1)をJS呼び出しスタックに追加します。時間(〜0)
それを実行します。 (コンソールに1を印刷)-時間(〜0)
SetTimeout(function(){console.log( "2");}、3000);の追加呼び出しスタックに。 -時間(〜0)
イベントループに移動して、タイマーを開始します。 -時間(3秒)
SetTimeoutは非同期関数であるため、イベントループに移動します。
Console.log(3)をJS呼び出しスタックに追加します。時間(〜0)
それを実行します。 (コンソールに3を印刷)時間(〜0)
SetTimeout(function(){console.log( "4");}、1000);の追加呼び出しスタックに。時間(〜0)
イベントループに移動して、タイマーを開始します。 -時間(1秒)
1秒のタイマーが終了すると、コールスタックに戻り、実行されます。
呼び出しスタックが実行します。 (コンソールに4を印刷)-時間(〜0)
3秒のタイマーが終了すると、コールスタックに戻り、実行されます。
呼び出しスタックが実行します。 (コンソールに2を印刷)-時間(〜0)
同期と呼んでいるのは、一度に1つのことしか実行できないJS呼び出しスタックです。
20ステップのプロセスにすることもできましたが、理解しやすいように12で十分です。
定義-マルチスレッド:マルチスレッドは、独立して実行するがプロセスリソースを共有するように、プロセスのコンテキスト内に複数のスレッドが存在できるようにする実行モデルの一種です。その意味で、JavaScriptは完全にマルチスレッドです。
let Ar;
Ar = []
function multiapp(ar,w,n) {
ar.clear;
for (let i = 0; i < n; i++)
setTimeout(function(){ar.Push(w)},i);
}
+function fn() {
//Thread 1
setTimeout(() => multiapp(Ar,1,10),100)
//Thread 2
setTimeout(() => multiapp(Ar,2,10),100)
}()
setTimeout(function(){console.log('Ar(1) = ', Ar.filter((i) => i == 1).length,'Ar(2) = ', Ar.filter((i) => i == 2).length,' Ar = ',Ar)},2000);
//Ar(1) = 10 Ar(2) = 10 Ar = [ 1, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 ]`
どうやら、スレッド1は、スレッド2とは独立して、独自のスタックを開始および実行するようです。2つのスレッドが同じコンテキストオブジェクトインスタンスArへのアクセスを共有し、未知の方法で変更します。 Javaアトミックプリミティブとまったく同じように動作します。