概述
node.js 事件循环
by Oluwaseun Omoyajowo
通过Oluwaseun Omoyajowo
走进Node.js事件循环 (Walking Inside the Node.js Event Loop)
NodeJS Event loop is perhaps one of the most misunderstood concepts in node. Unfortunately most articles online are not helping. Until a few days ago I also had the wrong idea of how Event loop works thanks to Daniel Khan’s article. Daniel highlighted some of these misconceptions and also explained the realities. I will just point out the most popular below and you can go over Daniel’s article after and read everything in full.
NodeJS事件循环可能是节点中最容易被误解的概念之一。 不幸的是,大多数在线文章都无济于事。 直到几天前,由于Daniel Khan的文章 ,我对Event循环的工作方式也有一个错误的认识。 丹尼尔强调了其中一些误解,并解释了现实。 我将在下面指出最受欢迎的内容,之后您可以阅读Daniel的文章 ,并完整阅读所有内容。
“The Event loop runs in a separate thread in the user code. There is a main thread where the JavaScript code of the user (userland code) runs in and another one that runs the event loop. Every time an asynchronous operation takes place, the main thread will hand over the work to the event loop thread and once it is done, the event loop thread will ping the main thread to execute a callback.” — This is WRONG
“ 事件循环在用户代码中的单独线程中运行。 有一个主线程运行用户JavaScript代码(用户域代码),另一个运行事件循环。 每次执行异步操作时,主线程都会将工作移交给事件循环线程,一旦完成,事件循环线程将对主线程执行ping操作以执行回调。 ” —这是错误的
This basically had been my own idea of Event loop, so I decided to do research and go deeper. In this article I will be explaining how everything happens with a general example.
这基本上是我自己对事件循环的想法,因此我决定进行研究并做进一步的研究。 在本文中,我将通过一个通用示例来说明一切是如何发生的。
To get started, Create a JavaScript file save it with whatever name you like, mine is ‘index.js’. Type or copy and paste the following codes inside the file.
首先,创建一个JavaScript文件,用您喜欢的任何名称保存它,我的名字是'index.js'。 在文件中键入或复制并粘贴以下代码。
const fs = require('fs');
const setTimeOutlogger = ()=>{ console.log('setTimeout logger');}const setImmediateLogger = ()=>{ console.log('setImmediate logger');}
//For timeout setTimeout(setTimeOutlogger, 1000);
//File I/O operationfs.readFile('test.txt', 'utf-8',(data)=>{ console.log('Reading data 1');});fs.readFile('test.txt', 'utf-8',(data)=>{ console.log('Reading data 2');});fs.readFile('test.txt', 'utf-8',(data)=>{ console.log('Reading data 3');});fs.readFile('test.txt', 'utf-8',(data)=>{ console.log('Reading data 4');});fs.readFile('test.txt', 'utf-8',(data)=>{ console.log('Reading data 5');});
//For setImmediatesetImmediate(setImmediateLogger);setImmediate(setImmediateLogger);setImmediate(setImmediateLogger);
Create a text file, ‘.txt’ in the same directory and save it with whatever name you like. Mine is ‘test.txt’. Inside this file type anything you like.
在同一目录中创建一个文本文件“ .txt”,并使用您喜欢的任何名称保存。 我的是“ test.txt”。 在此文件中键入您喜欢的任何内容。
Before you run the JavaScript file, if you are able to guess the order of the console output then *thumbs up for you*. My own output:
在运行JavaScript文件之前,如果您能够猜测控制台输出的顺序,那么*为您准备好*。 我自己的输出:
setImmediate loggersetImmediate loggersetImmediate loggerReading data 1Reading data 2Reading data 3Reading data 4Reading data 5setTimeout logger
It is possible for yours to be different, depending on the size of file you are reading, and the content in the ‘.txt’ file you created.
根据所读取文件的大小以及所创建的“ .txt”文件中的内容,您的文件可能会有所不同。
So what happened in the Event loop when you ran the code?
那么,当您运行代码时,事件循环中发生了什么?
When Node.js starts, it initializes the Event loop, processes the provided input script which may make async API calls, then begins processing the Event loop. There is only one thread and that is the thread Event loop runs on. Event loop works in a cyclical order, with different phases. The order of operation of Event loop is shown below.
Node.js启动时,它将初始化事件循环,处理提供的输入脚本(可能进行异步API调用),然后开始处理事件循环。 只有一个线程,并且是事件循环在其上运行的线程。 事件循环以周期性的顺序工作,并具有不同的阶段。 事件循环的操作顺序如下所示。
There are six phases in the Event loop but one works internally. Below is an overview of each phase from the Node.js doc.
事件循环有六个阶段,但一个阶段在内部工作。 以下是Node.js 文档中每个阶段的概述。
timers: this phase executes callbacks scheduled by
setTimeout()
andsetInterval()
.计时器:此阶段执行
setTimeout()
和setInterval()
安排的回调。I/O callbacks: executes almost all callbacks with the exception of close callbacks, the ones scheduled by timers, and
setImmediate()
.I / O回调:执行几乎所有的回调,但close回调,计时器安排的回调和
setImmediate()
。- idle, prepare: only used internally. 空闲,准备:仅在内部使用。
- poll: retrieve new I/O events; node will block here when appropriate. 轮询:检索新的I / O事件; 适当时,节点将在此处阻塞。
check:
setImmediate()
callbacks are invoked here.close callbacks: such assocket.on(‘close’)
.检查:
setImmediate()
回调在这里被调用。关闭回调:例如socket.on('close')
。
计时器 (Timers)
From our example, we setTimeout
to 1s before invoking timeOutLogger
function. This is the first phase (not exactly the first but from our example it is) of the event loop. The timer sets the threshold at which the callback will be executed.
从我们的例子中,我们setTimeout
调用之前1S timeOutLogger
功能。 这是事件循环的第一个阶段(不完全是第一个阶段,但在我们的示例中是)。 计时器设置将执行回调的阈值。
It is important to note that each phase has a first in, first out (FIFO) queue of callbacks to be executed.
重要的是要注意,每个阶段都有要执行的回调的先进先出(FIFO)队列。
I / O回调 (I/O callbacks)
This phase executes system error callbacks such as Transmission Control Protocol (TCP) socket connection error ECONNREFUSED.
While this phase is called I/O callback, understand that normal I/O operation callbacks are executed in the poll phase. I will dive into this next. In our example no callback was queued here.
此阶段执行系统错误回调,例如传输控制协议(TCP)套接字连接错误ECONNREFUSED.
虽然此阶段称为I / O回调,但是请理解,正常的I / O操作回调是在轮询阶段执行的。 接下来,我将深入探讨这一点。 在我们的示例中,没有回调在这里排队。
轮询 (Poll)
This phase is where most of the work is done. From the Node.js doc, the poll phase basically does two things:
这个阶段完成了大部分工作。 根据Node.js文档,轮询阶段基本上可以完成两件事:
- Executing scripts for timers whose threshold has elapsed 为阈值已过的计时器执行脚本
- Processing events in the poll queue 处理轮询队列中的事件
Following our example in this phase, there is currently an empty queue since fs.readFile
has not completed. While waiting, the timer 1s
threshold set earlier hasn’t elapsed. The event loop checks for callbacks queued by setImmediate()
in the check phase. There are three callbacks from our example queued by setImmediate()
. The event loop enters the check phase.
在此阶段的示例之后,由于fs.readFile
尚未完成,因此当前存在一个空队列。 等待时,尚未超过之前设置的计时器1s
阈值。 事件循环在检查阶段检查由setImmediate()
排队的回调。 在我们的示例中,由setImmediate()
排队的三个回调。 事件循环进入检查阶段。
检查一下 (Check)
In the check phase, the event loop executes all callbacks in the queue, hence the console output order in our example.
在检查阶段,事件循环执行队列中的所有回调,因此在我们的示例中为控制台输出顺序。
After executing all callbacks in the check queue and no timer threshold has been reached. But there are queued callbacks in the poll phase already from fs.readFile. Event loop executes all callbacks (event loops blocks) until maximum or the queue is empty again. Here is the thing, while executing the callbacks it is possible for timer threshold to elapse. And with new timer callback ready to be executed, the timer will have to wait for poll callbacks to execute, causing extra delays. This is one of the reasons why it is advisable not to do so many things inside your callbacks. After executing the poll queue callbacks, event loop immediately wraps back to the timer to execute the callback.
执行检查队列中的所有回调后,尚未达到计时器阈值。 但是在轮询阶段已经有来自fs.readFile的排队回调。 事件循环执行所有回调(事件循环块),直到达到最大值或队列再次为空。 这就是事情,执行回调时,可能会超过计时器阈值。 在准备好执行新的计时器回调时,计时器将不得不等待轮询回调执行,从而导致额外的延迟。 这是为什么建议不要在回调中做很多事情的原因之一。 执行轮询队列回调后,事件循环立即回绕到计时器以执行回调。
Note: To prevent the poll phase from starving the event loop, libuv also has a hard maximum (system dependent) before it stops polling for more events.
注意:为防止轮询阶段使事件循环陷入饥饿, libuv在停止轮询更多事件之前还具有一个硬最大值(取决于系统)。
结论 (Conclusion)
While there are still many things going on behind the scene inside event loops, I hope have been able to give you an overview of inside the Node.js event loop. If you have any question or like to make correction kindly write it in the response. I will answer as soon as I can or update the article.
尽管事件循环内部还有很多事情要做,但我希望能够为您提供Node.js事件循环内部的概述。 如果您有任何疑问或想进行更正,请在回复中写下。 我将尽快答复或更新文章。
Thanks for reading. I’m Oluwaseun Omoyajowo, Freelance full-stack web developer. Get in touch! Twitter LinkedIn Github Facebook
谢谢阅读。 我是Oluwaseun Omoyajowo,自由职业者全栈Web开发人员。 保持联系! Twitter LinkedIn Github Facebook
翻译自: https://www.freecodecamp.org/news/walking-inside-nodejs-event-loop-85caeca391a9/
node.js 事件循环
最后
以上就是怡然仙人掌为你收集整理的node.js 事件循环_走进Node.js事件循环 走进Node.js事件循环 (Walking Inside the Node.js Event Loop)的全部内容,希望文章能够帮你解决node.js 事件循环_走进Node.js事件循环 走进Node.js事件循环 (Walking Inside the Node.js Event Loop)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复