ブラウザとノードのイベントループの違い

4633 ワード

イベントループは、jsではありふれた話題ですが、ブラウザとノードではイベントループの実行メカニズムが異なり、ブラウザのイベントループはHTML 5で定義された仕様ですが、ノードではlibuvライブラリで実現され、混同してはいけません.
まず、簡単なイベントループペンの問題を見てみましょう.
function sleep(time) {
    let startTime = new Date();
    while (new Date() - startTime < time) {}
    console.log('');
}

setTimeout(() => {
    console.log('timeout1');
    setTimeout(() => {
        console.log('timeout3');
        sleep(1000);
    });
    new Promise((resolve) => {
        console.log('timeout1_promise');
        resolve();
    }).then(() => {
        console.log('timeout1_then');
    });
    sleep(1000);
});
     
setTimeout(() => {
    console.log('timeout2');
    setTimeout(() => {
        console.log('timeout4');
        sleep(1000);
    });
    new Promise((resolve) => {
        console.log('timeout2_promise');
        resolve();
    }).then(() => {
        console.log('timeout2_then');
    });
    sleep(1000);
});

異なる環境では、出力の結果も異なります.
  • ブラウザからの出力:
  • timeout1
    timeout1_promise
    
    timeout1_then
    timeout2
    timeout2_promise
    
    timeout2_then
    timeout3
    
    timeout4
    
    
  • ノード環境での出力:
  • timeout1
    timeout1_promise
    
    timeout2
    timeout2_promise
    
    timeout1_then
    timeout2_then
    timeout3
    
    timeout4
    
    

    次に、ブラウザとノードの時間サイクルの違いを見てみましょう.
    1.タスクキュー
    ブラウザ環境
    ブラウザ環境での非同期タスクは、マクロタスク(macroTask)とマイクロタスク(microTask)に分けられます.
  • マクロタスク(macroTask):script中コード、settimeout、setInterval、I/O、UI render;
  • マイクロタスク(microTask):Promise、Object.observe、MutationObserver.

  • 実行条件が満たされると、マクロタスク(macroTask)とマイクロタスク(microTask)はそれぞれ対応するキューに入れられる:マクロキュー(Macrotask Queue)とマイクロキュー(Microtask Queue)で実行を待つ.
    ノード環境
    Node環境では、ブラウザ環境よりもタスクタイプが複雑です.
  • microTask:マイクロタスク;
  • nextTick: process.nextTick ;
  • timers:条件を満たすsettimout、setIntervalコールバックを実行する;
  • I/O callbacks:完了したI/O操作のコールバック関数があるか、前輪からのpollが残っているか.
  • poll:まだ完了していないI/Oイベントを待ち、timersやタイムアウト時間などで待機を終了する;
  • check:setImmediateのコールバックを実行する;
  • close callbacks:すべてのclosing handlesを閉じ、いくつかのoncloseイベント;
  • idle/prepareなど:無視できます.

  • これにより、イベントループを実行するための対応するタスクキューTimers Queue、I/O Queue、Check Queue、Close Queueが生成される.
    2.プロセスの実行
    ブラウザ環境
    まずの タスクを し、その すべてのマイクロタスク、1つのマクロタスク、すべてのマイクロタスク、1つのマクロタスク......
  • メイン スレッドのタスクを する.

  • Microstask Queueからタスク をクリアするまで り す.

  • Macrotask Queueの1つを り して する.

  • 2と3を り す.


  • の に してください.
  • ブラウザページでは スレッドにコードがないと えられ、それぞれのコードは したtaskであり、 ので したmicroTaskを してから のの コードを する.
  • MicroTaskが され けている はmicroTask、「カード 」macroTaskを し ける.
  • のバージョンではブラウザの が と しない があり、 に しないかjsとhtmlの の と している がある.
  • PromiseのthencatchこそmicroTaskで、それ の コードは います;
  • ブラウザ APIはリストされていない.

  • ノード
    ループの
    のループに る に、 の を います.
  • タスク;
  • を す;
  • タイマーの ;
  • process.nextTick().

  • ループの
    ループ のアクション:
  • カレントサイクル のTimers Queueをクリアし、NextTick Queueをクリアし、Microstask Queueをクリアする.
  • カレントサイクル のI/O Queueをクリアし、Nexttick Queueをクリアし、Microstask Queueをクリアする.
  • カレントサイクル のCheck Queueをクリアし、Nexttick Queueをクリアし、Microstask Queueをクリアする.
  • カレントサイクル のClose Queueをクリアし、Nexttick Queueをクリアし、Microstask Queueをクリアする.
  • に る.

  • nextTick はPromiseなどのmicroTaskより く、setTimeoutおよびsetInterval setImmediateより いことがわかる.

    プロセス で、 の に してください.
  • timersフェーズ に された setImmediateこのラウンドのcheckフェーズで され、timersフェーズで された setTimeouttimersが り されたため、 のラウンドに み、checkフェーズ timersタスクは じである.
  • setTimeout setImmediate いがsetTimeout(fn,0)の の が に0 になることは であるため、 に したsetTimeout(fn,0)に べてsetImmediateのコールバック に する がある.

  • まとめ
    ブラウザとノードでのイベントループの いは されやすく、 は のように されています.
    ブラウザ :
    while (true) {
             .shift();
                 ();
    }
    

    ノード :
    while (true) {
        loop.forEach((  ) => {
                  ();
            nextTick    ();
            microTask    ();
        });
        loop = loop.next;
    }
    

    にははっきりしていると いますが、 か があれば で することができます.
    の の は のとおりです.https://segmentfault.com/a/1190000013660033?utm_source=channel-hottest