プロセスとスレッド
JSは、シングルスレッドの実行、それのスレッドは何ですか?
本質的に、そして確かにプロセスについて言わなければならない、スレッドの話、2つの用語があるCPUの作業時間スライス記述。
これは、CPUの中のプロセスについて説明し、負荷にし、必要なコンテキスト保存時間と実行コマンドをプログラムに代わってアプリケーションに、。スレッドは、より小さな単位の過程にある命令を実行するのに必要な時間の期間を記述する。
あなたはタブページを開いたときにこれらの概念は、実際には、プロセスを作成することです、ブラウザを取得するプロセスは、以下のような複数のスレッド、持つことができ、レンダリングスレッド、JSエンジンスレッド、HTTPリクエストスレッドようにしています。あなたが要求を開始すると、実際には、それがスレッドを作成することで、要求の終了後に、スレッドが破壊された可能性があります。
2つのスレッドがある番組UIレンダリング、防止することができるJSの実行時に、JSエンジンスレッドおよびレンダリングスレッド上記相互に排他的なのです。JSは、DOMを変更することができJS UIスレッドでの実装のコースがまだ動作している場合、それは危険なレンダリングUIにつながる可能性があるためです。この利点の1つは、実際にJSにシングルスレッド、シングルスレッドの実行のおかげで、あなたは、コンテキストスイッチの時間節約、メモリ保存全くロックの問題に到達することはできません。
実行スタック
これは、実行スタックのストレージ関数呼び出しとみなすことができるスタック構造以下、最後のアウトの原則
例えば、次のコードを実行します。
関数foo(B){ せ = 5 戻りを * B + 10 } 関数バー(X){ せY = 3 戻り FOO(X * Y) } はconsole.log(バー(6))
最初のスタックからポップされた後、それは最後のアウトの原則によれば、第1の主な機能を実行した後、私たちのコードを実行されます、関数が実行されます。
また、実行スタックにエラーの痕跡を見つけることができます
関数fooは(){ スロー 新しいエラー(' エラー' ) } 関数bar(){ FOO() } バーを()
あなたは明確にfooという関数が機能バーに呼ばれ、関数fooのエラーを見ることができます
保存できる機能スタックが限られているので、我々は、再帰を使用する場合は、リリースされてあまりにも多くを保存していないの機能と、状況スタックオーバーフローが発生します。
ブラウザのイベントループ
上記のコードを通して、私たちはどのように行うにはときに我々が実行JSコードは、その後、非同期コードが発生した関数にスタックを実行するために実際にあることを知っていますか?実際には、非同期コードに直面したとき、それがされ中断とを追加したときには、実行する必要があるタスク(タスクの様々な)キュー。実行スタックが空になると、イベントループは、実行されるタスクキューコードニーズから来ると実行スタックの実装に配置され、本質的にその結果JS非同期または同期動作を。
異なるタスクがタスクキューの異なるソースに割り当てられ、タスクソースに分割することができるマイクロタスク(マイクロタスク) とマクロタスク(マクロタスク)。ES6仕様では、マイクロタスクはマクロタスクと呼ばれるタスク、ジョブと呼ばれます。次のコードの実行シーケンスで見てみましょう
console.log( 'スクリプト開始' ) 非同期関数async1(){ のawait async2() はconsole.log( 'async1端' ) } 非同期関数async2(){ にconsole.log( 'async2端' ) } async1() のsetTimeout(関数(){ にconsole.log( 'のsetTimeout' ) }、 0 ) 新しいプロミス(決意=> { にconsole.log( '約束' ) 解決() }) .then(関数(){ にconsole.log( 'promise1' ) }) .then(関数(){ にconsole.log( 'promise2' ) }) はconsole.log( 'スクリプト末端' ) // スクリプト開始- > async2エンド- >プロミス- >スクリプトの終了 // - > promise1 - > promise2 - > async1の終わり- >のsetTimeout
私たちは、上記のコードを見て非同期とのawait私たちが呼ぶとき、実行順序async1機能を、出力はすぐにasync2終了し、関数が返す約束次の出会いは、待つ時間は、スレッドが実行始まるようになりますasync1の外側をコードなので、私たちすることができますすべてのawaitとしてLETアウトスレッドのロゴ。
同期コードが実行されると、その後、それがために戻った後、非同期コードのすべてを実行するために行く待つ返さの実装の位置約束の解決それがなり、機能を解決し、次には、以下の当社の実施するために、スローされたマイクロキューを新たにします約束二うちその後コールバックは、2つのすべての終了後に、位置処理の戻り値を待つために戻るであろうときにコールバック、今回のように見ることができる.then Promise.resolve(戻り値)()その後のawaitのコードは、すべての中にラップされます、その後ので、コールバック関数にconsole.log(「async1側が」)で優先されるのsetTimeout
次の関数の非同期に似た2つのコード
新しい新しい約束((解決、拒否)=> { はconsole.log(「末端async2」) // Promise.resolve()タスクキューテールへのマイクロコード // 解決-タスクキューテールを挿入し、再び ((Promise.resolveを解決) ) })。次に、(() => { にconsole.log( '末端Async1' ) })
場合であること、のawaitが続く約束は、その後、Async1エンドは 3つの待つように目盛りを実行するために、そして、実際には、パフォーマンスが比較的少し遅いままです。だから、V8チームは、ダニ、二次ダニを減らすためにエンジンの下部に、ノード8で3回バグを描画します。このような行為は違法であるが、実際にはノルムは、当然のことながら、仕様を変更することもでき、これはPR V8チームで、今、このアプローチに合意されています。しかし、ビュー業績ブラウザの私たちの観点から、それは変更していないようでした。
したがって、イベントループを次のように実行順序は次のとおりです。
- 第一に属する同期コード、実行マクロタスク
- すべての同期コードを実行終了したら、実行スタックが空である、非同期コードを実行する必要があるかどうかを確認してください
- すべての実行マイクロタスクを
- すべてのマイクロタスクを実行が終了したら、必要に応じて、ページをレンダリングします
- そして、次のラウンドの開始イベントループ、マクロタスク非同期コードの実行を。それはsetTimeoutメソッドコールバックです
だから、にもかかわらず上記のコードのsetTimeoutはに書いた約束の前に、しかし、理由の約束タスクに属しミクロマクロタスクのsetTimeoutに属し以上が印刷されますので、。
マイクロタスクが含まれます:process.nextTick、約束、MutationObserverを
マクロタスクには、スクリプト、のsetTimeout、のsetIntervalを、setImmediate、I / O、UIのレンダリング
ここでは多くの人々がより速くタスクにミクロマクロタスクという誤解を持って、実際には、間違っています。マクロタスクが含まれているため、ブラウザが最初のマクロタスクを実行します、その後、何か非同期コードは、最初のマイクロタスクが実行されますがあります。 script