この記事では、node のイベント ループ メカニズムを理解します。一定の参考値があるので、困っている友達が参考になれば幸いです。
フロントエンド開発は JavaScript と切り離すことができません。JavaScript は Web フロントエンド言語であり、主に Web 開発で使用され、ブラウザーによって解析および実行されます。 js の役割はフロントエンド開発に限定されず、サーバーサイド開発 (nodejs) にも使用できます。理想と野心を持ったフロントエンド担当者として、視野を広げてサーバーサイド開発言語をマスターしたい場合、nodejs は非常に良い選択です。
関連する推奨事項: 「nodejs チュートリアル 」
js 開発方法をマスターしているので、node を簡単に始めることができ、npm パッケージ管理ツールも簡単に使用できます。開発エクスペリエンスが大幅に向上します。 Nodejs は非同期ノンブロッキング I/O の動作方式で有名で、その処理メカニズムはイベント ループと呼ばれます。
ノードのイベントループの仕組みを理解することで、ノードのイベント処理方法や非同期イベントの実行タイミングをより深く理解できるようになります. この記事では主にnodejsのイベントループの仕組みを解説し、その後のノードの学習の基礎を作ります。
前述したように、JavaScript は主に Web 開発で使用される Web フロントエンド言語であり、ブラウザによって解析されて実行されます。 , 一方、node .js は Chrome V8 エンジンに基づいた JavaScript 実行環境です。したがって、nodejs は言語、ライブラリ、またはフレームワークではなく、js 実行環境です。簡単に言うと、node は js コードを解析して実行できます。以前は、ブラウザのみが JS を解析して実行できましたが、現在では、node はブラウザなしで完全に JS を実行できるようになります。
node.js とブラウザー js の間には多くの違いがあります。たとえば、ブラウザーの js には ecmascript、BOM、および DOM が含まれますが、nodejs の js には BOM、DOM がなく、emcscript のみが含まれます。また、node の js 実行環境は、ファイルの読み取りと書き込み、ネットワーク サービスの構築、ネットワーク通信、http サーバーなど、js のサーバー レベルの操作 API をいくつか提供します。これらの API のほとんどは、コア モジュールにパッケージ化されています。また、nodeのイベントループの仕組みはブラウザjsのイベントループの仕組みとは異なります。
ブラウザでの JS イベント ループについてはすでに誰もがよく知っているので、比較のためにここで簡単に説明します。
js が実行されると、同期タスクと非同期タスクはそれぞれ異なる実行環境に入ります。同期タスクはメインスレッド、つまりメイン実行スタックに入り、非同期タスク (ajax リクエスト、settimeout、setinterval、poromise.resolve()、など) タスクキューに入ります。 ajax リクエスト、settimeout、setinterval など、さまざまな非同期タスクがさまざまなタスク キューにプッシュされます。これらのタスクはマクロ タスク キュー (マクロ タスク) にプッシュされ、Promise 関数はマイクロ タスク キューにプッシュされます (マイクロタスク)。全体的なイベント ループ プロセスは次のとおりです。
同期コードが実行されると、メイン実行スタックが空になり、非同期タスクを実行する準備が始まります。
メイン スレッドは、マイクロタスク キューが空かどうかを確認します。空でない場合は、キュー内のすべてのマイクロタスクを走査して実行し、マイクロタスク キューをクリアしてから、マクロのタスクキューを確認してください。マイクロタスク キューが空の場合は、次のステップに直接進みます。
メイン スレッドはマクロ タスク キューを走査し、マクロ タスク キュー内の最初のマクロ タスクを実行します。実行中にマクロ タスクまたはマイクロ タスクが発生した場合、処理を続行します。対応するタスク キューにプッシュします。マクロ タスクが実行されるたびに、マイクロ タスク キューを走査してクリアする必要があります。
レンダリング操作を実行し、ビューを更新します
次のイベント ループを開始し、2 つのタスク キューがクリアされるまで上記の手順を繰り返します。
影響をさらに深くするために、小さな例を取り上げます。次のコードを見てください。何が出力されますか:
var le=Promise.resolve(2); console.log(le) console.log('3') Promise.resolve().then(()=>{ console.log('Promise1') setTimeout(()=>{ console.log('setTimeout2') },0) }) setTimeout(()=>{ console.log('setTimeout1') Promise.resolve().then(()=>{ console.log('Promise2') }) },0);
上記のイベント ループ プロセスを使用して分析します:
したがって、出力結果は次のようになります: Promise {
ブラウザでの実行結果は以下の通りです:
があります。ノードのイベント ループの合計 6 ステージ。この 6 つのステージは、イベント処理が完了するまでイベント ループ内で順番に実行されます。 6 つのステージのシーケンス図は次のとおりです。
六个阶段分别是:
事件循环中,每当进入某一个阶段,都会从该阶段对应的回调队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,该阶段就会终止,然后检查NextTick队列和微任务队列,将其清空,之后进入下一个阶段。
这里面比较关键的是poll阶段:
同样的举个大大的,看看以下代码会输出什么:
console.log('start') setTimeout(() => { console.log('timer1') Promise.resolve().then(function() { console.log('promise1') }) }, 0) setTimeout(() => { console.log('timer2') Promise.resolve().then(function() { console.log('promise2') }) }, 0) Promise.resolve().then(function() { console.log('promise3') }) console.log('end')
利用node事件循环分析呗:
因此输出顺序是:start,end,promise3,timer1,promise1,timer2,promise2,如果能正确回答出来说明对node的循环机制有了大体的了解,实际node输出结果确实是这样:
那如下代码会输出什么呢?
process.nextTick(function(){ console.log(7); }); new Promise(function(resolve){ console.log(3); resolve(); console.log(4); }).then(function(){ console.log(5); }); process.nextTick(function(){ console.log(8); });
继续分析:
因此最终输出是:3,4,7,8,5,需要记住,process.nextTick 永远大于 promise.then的优先级
还有一个大家很容易混淆的点就是setTimout和setImmediate的执行时机,根据上面描述的node事件循环机制,setImmediate()应该在check阶段执行 与 而setTimeout在timer阶段执行,理论上setTimout比setImmediate先执行,看下面的代码:
setTimeout(() => console.log(1),0); setImmediate(() => console.log(2));
执行结果是什么?1,2 还是 2,1,其实都有可能,看实际node运行的结果:
可以看到两次执行的结果不一样,为什么呢?原因在于即使setTimeout的第二个参数默认为0,但实际上,Node做不到0秒就执行其回调,最少也要4毫秒。那么进入事件循环后,如果没到4毫秒,那么timers阶段就会被跳过,从而进入check阶段执行setImmediate回调,此时输出结果是:2,1;
如果进入事件循环后,超过4毫秒(只是个大概,具体值并不确定),setTimeout的回调会出现在timer阶段的队列里,回调将被执行,之后再进入poll阶段和check阶段,此时输出结果是:1,2
那如果两者在I/O周期内调用,谁先执行呢?看一下代码:
const fs = require('fs') fs.readFile('./test.txt', 'utf8' , (err, data) => { if (err) { console.error(err) return } setTimeout(() => { console.log('timeout'); }, 0); setImmediate(() => { console.log('immediate'); }); })
实际上,node中输出的结果总是immediate先输出,timeout后输出。因为I/O回调是在poll阶段执行,当回调执行完毕之后队列为空,发现存在setImmediate的回调就会进入check阶段,执行完毕后,再进入timer阶段。
本文结合代码示例,对node的事件循环机制做了比较详细描述。通过这篇文章,应该可以了解浏览器的事件循环机制是怎样的,node的循环机制是怎样的,以及nextTick和micro队列的优先级,setTimout和setImmediate执行时机等一些容易混淆的知识点。文章中不足和不对之处,欢迎在评论区交流讨论,一起探索,谢谢。
更多编程相关知识,请访问:编程入门!!
以上がNodejsのイベントループの仕組みを詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。