序文:今回は主にJsのイベントループの仕組み、同期、非同期タスク、マクロタスク、マイクロタスクについての理解を整理します。今のところまだ多少の逸脱や誤りがある可能性が高いです。もしそうなら、私の間違いを訂正していただければ幸いです。 1. イベント ループとタスク キューの理由:まず、JS はシングルスレッドなので、この設計は合理的です。DOM が一方側で削除され、もう一方に追加された場合、ブラウザはどのように処理するのでしょうか? 引用: 「シングルスレッドとは、タスクがシリアルであり、次のタスクは前のタスクの実行を待つ必要があるため、待機時間が長くなる可能性があることを意味します。ただし、ajax ネットワーク リクエスト、setTimeout 時間遅延、DOM イベントによるユーザー操作などのタスクにより、これらのタスクは CPU を消費せず、リソースの無駄になります。そのため、非同期性が現れます。タスクを対応する非同期モジュールに割り当てて処理することで、メイン スレッドの効率が大幅に向上し、他の操作を並列処理できます。非同期処理が完了し、メイン スレッドがアイドル状態になると、メイン スレッドは対応するコールバックを読み取り、後続の操作を実行して、CPU の使用率を最大化します。このとき、同期実行と非同期実行の概念が現れます。同期実行とは、メイン スレッドがタスクを順番にシリアルに実行することを意味し、非同期実行とは、CPU が待機をスキップして後続のタスクを最初に処理することを意味します (CPU は、ネットワーク モジュール、タイマーなどと並列にタスクを実行します)。これにより、タスク キューとイベント ループが作成され、メイン スレッドと非同期モジュール間の作業が調整されます。 」 二、イベントループメカニズム:図: まず、JS 実行コードの動作は ステップ 1: メイン スレッドは同期環境である JS コードを読み取り、対応するヒープと実行スタックを形成します。 一般的な非同期操作には、ajax リクエスト、setTimeout、同様の onclik イベントなどがあります。 三つ、タスクキュー:同期タスクと非同期タスクはそれぞれ異なる実行環境に入ります。同期タスクはメインスレッド、つまりメイン実行スタックに入り、非同期タスクはタスクキューに入ります。 まず、名前の通りキューなので、 上の図に示すように、複数のタスク キューがあり、その実行順序は次のとおりです。 同じタスク キューでは、タスクはキューの順序に従ってメイン スレッドによって取り除かれます。 3.1 タスクキューの種類:タスクキューは マクロタスクには主に、スクリプト(コード全体)、setTimeout、setInterval、I/O、UIインタラクションイベント、setImmediate(Node.js環境)が含まれます。 マイクロタスクには主に、Promise、MutaionObserver、process.nextTick(Node.js 環境)が含まれます。 3.2 両者の違い: (1)ユニーク、イベントループ全体で1つだけ存在する。 PS: したがって、マイクロタスクキューは同期実行環境を形成できる。 マクロタスク (1)一意ではなく、一定の優先順位がある(ユーザーI/O部分の優先順位が高い) 3.3より詳細なイベントループプロセス
理解を深めるために簡単な例を見てみましょう。 console.log('1, time = ' + new Date().toString()) // 1. メインスレッドに入り、同期タスクを実行して、1 を出力します。 setTimeout(macroCallback, 0) // 2. マクロタスクキューに参加します // 7. このタイマーマクロタスクの実行を開始し、macroCallback を呼び出して 4 を出力します new Promise(function (resolve, reject) { //3. マイクロタスクキューに参加 console.log('2, time = ' + new Date().toString()) //4. このマイクロタスク内の同期コードを実行し、2を出力する 解決する() console.log('3, time = ' + new Date().toString()) //5. 出力3 }).then(microCallback) // 6. thenマイクロタスクを実行し、microCallbackを呼び出して5を出力する //関数定義関数macroCallback() { console.log('4, 時間 = ' + 新しい Date().toString()) } 関数microCallback() { console.log('5, 時間 = ' + 新しい Date().toString()) } 実行結果: 4、強力な非同期エキスパートプロセス.nextTick()これを初めて見たとき、見覚えがあると思いました。よく考えてみると、以前 Vue プロジェクトで 4.1 process.nextTick() はいつ呼び出されますか?特定のフェーズで process.nextTick() が呼び出されるたびに、イベント ループが続行される前に process.nextTick() に渡されるすべてのコールバックが解決されます。 イベントループでは、各ループ操作を イベント ループの理解を深めるために、他の人の例を借りてみましょう。 var flag = false // 1. 変数宣言 Promise.resolve().then(() => { // 2. then タスクをこのループのマイクロタスク キューに配布します console.log('then1') // 8. then マイクロタスクを実行し、then1 を出力します。この時点でフラグは true です flag = true }) 新しいPromise(resolve => { // 3. Promise 内の同期コードを実行する console.log('promise') 解決する() setTimeout(() => { // 4. タイマーのタスクをマクロタスクキューに入れる console.log('timeout2') // 11. タイマーマクロタスクを実行する。ここでは待機時間 10 が指定されているため、別のタイマータスクの後に実行されます}, 10) }).then(関数() { // 5. then タスクをこのループのマイクロタスク キューに配布します console.log('then2') // 9. then マイクロタスクを実行し、then2 を出力します。このティック ラウンドは終了します}) 関数 f1(f) { // 1. 関数宣言 f() } 関数 f2(f) { // 1. 関数宣言 setTimeout(f) // 7. `setTimeout` の `f` をマクロタスクキューに入れ、現在の `tick` ラウンドの実行を待機し、次のイベントループでそれを実行します} f1(() => console.log('f is:', flag ? 'asynchronous' : 'synchronous')) // 6. `f is: synchronized` を出力します f2(() => { console.log('timeout1,', 'f is:', flag ? 'asynchronous' : 'synchronous') // 10. タイマーマクロタスクを実行する}) console.log('このマクロタスクが実行されました') // 7. 印刷 実行結果: process.nextTick のコールバックは、現在のティックが実行された後、次のマクロ タスクが実行される前に呼び出されます。 公式の例: バーを付ける; // このメソッドは非同期シグネチャを使用しますが、実際にはコールバック関数を同期的に呼び出します someAsyncApiCall(callback) { callback(); } // `someAsyncApiCall` が完了する前にコールバック関数が呼び出されますsomeAsyncApiCall(() => { // `someAsyncApiCall` が完了したため、bar には値が割り当てられません console.log('bar', bar); // undefined }); バー = 1;
バーを付ける; 関数 someAsyncApiCall(コールバック) { process.nextTick(コールバック); } いくつかのAsyncApiCall(() => { console.log('bar', bar); // 1 }); バー = 1;
console.log('1'); // 1. メインスレッドの実行スタックにプッシュして1を出力します setTimeout(function () { //2. コールバック関数がマクロタスクキューに追加されます //7. 現在マイクロタスクキューは空なので、マクロタスクキューの最初の項目を取り出してこのタスクを実行します console.log('2'); // 出力 2 process.nextTick(function () { // 16. 最後のループが終了し、次のマクロタスクが開始される前に呼び出され、出力3が返されます。 コンソールログ('3'); }) 新しいPromise(関数(resolve) { //8. このプロミスの同期タスクを実行し、出力4、状態が解決される コンソールログ('4'); 解決する(); }).then(function (){//9. 非同期メソッドthenを検出し、そのコールバック関数をマイクロタスクキューに追加します。console.log('5'); // 10. マイクロタスクキューの最初の項目(このthenのコールバック)を取り出し、それを実行して5を出力します。 }) }) process.nextTick(function () { // 11. イベントループが終了したら、nextTick() のコールバックを実行して 6 を出力します。 コンソールログ('6'); }) 新しいPromise(関数(resolve) { //3. Promiseの同期タスクを実行して7を出力すると、状態が解決済みに変わります。 コンソールログ('7'); 解決する(); }).then(function () { //4. 非同期メソッドを検出し、そのコールバック関数をマイクロタスクキューに追加します console.log('8'); //6. メインスレッドが実行され、マイクロタスクキューの最初の項目が取り出され、そのコールバック関数が実行スタックにプッシュされ、8が出力されます }) setTimeout(function () { //5. コールバック関数がマクロタスクキューに追加されます //12. この時点で、マイクロタスクキューは空であり、マクロタスクの実行が開始されます console.log('9'); // 出力 9 process.nextTick(function () { // 17. この時点では、マイクロタスクとマクロタスクのキューは両方とも空なので、ループは自動的に終了し、このコールバックを実行して10を出力します。 コンソールログ('10'); }) 新しいPromise(関数(resolve) { //13. この Promise の同期タスクを実行し、出力 11 と状態の変更を実行します。console.log('11'); 解決する(); }).then(function (){//14. then非同期メソッドを検出し、それをマイクロタスクキューに追加します console.log('12');//15. マイクロタスクキューの最初の項目を取り出し、このthenマイクロタスクを実行して12を出力します }) }) 実行結果: このプロセスは詳細に説明されています。
仕上げる!インスピレーションが湧いたらすぐに書き留めて、後で問題がないか確認します。間違いがあればご指摘いただければ幸いです。 簡単な例を分析してみましょう。 コンソールログ('0'); タイムアウトを設定する(() => { コンソールログ('1'); 新しいPromise(function(resolve) { コンソールログ('2'); 解決する(); })。そして()=>{ コンソールログ('3'); }) 新しいPromise(resolve => { コンソールログ('4'); (i=0;i<9;i++) の場合{ i == 7 && 解決(); } コンソールログ('5'); }).then(() => { コンソールログ('6'); }) })
コード実行結果: JavaScript のイベント ループ メカニズムの分析に関するこの記事はこれで終わりです。JavaScript のイベント ループ メカニズムに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: HTML ハイパーリンク スタイル (4 つの異なる状態) の設定例
序文MySQL のマスター/スレーブ レプリケーション関係は、厳密には「同期」または「マスター/スレ...
画像タグは、Web ページに画像を表示するために使用されます。 HTML/XHTML 画像 <...
まずプロジェクトの成果物を構成するスタートアップ項目の設定 Tomcatサービスを作成する開始したい...
最近の事例をお話ししましょう。オンライン Alibaba Cloud RDS 上のゲーム ログ ライ...
通常、vue プロジェクトではルーティングを使用します。vue-router は vue.js の公...
かなり前の記事で、 -webkit-box-reflectプロパティについて説明しました。リフレクシ...
目次概要達成方法具体的な実装評価関数の終了を決定する生成関数の範囲変換関数マップフィルター割り込み機...
序文以前、ローディングスタイルのコンポーネントを作成しました。コードの再利用性を実現するために、この...
導入から始めず、いきなり本題に入りましょう。通常の背景ぼかし効果は次のとおりです。 プロパティを使用...
<iframe src="./ads_top_tian.html" all...
HTMLページジャンプ: window.open(url, "", "...
2 列レイアウトはプロジェクトでよく使用されます。この効果を実現する方法はたくさんあります。 しかし...
目次1. proxy_pass を設定した後に Nginx が 404 を返す問題のトラブルシューテ...
目次1. はじめに2. インストール3. 基本的な使い方3.1、-rパラメータ3.2、-aパラメータ...
目次1. インストール2. カプセル化に問題はない3. ファイルを作成する4. アドレス設定をリクエ...