node的事件循环与js的区别,nodejs中的事件循环的执行顺序
什么是事件周期?本文介绍了Node中的事件循环,希望对你有所帮助!
node.js速度课程简介:进入学习
什么是事件循环?
虽然JavaScript是单线程的,但是事件循环尽可能使用系统内核,允许Node.js执行非阻塞I/O操作。
尽管大多数现代内核都是多线程的,但它们可以在后台处理多线程任务。当一个任务完成后,内核告诉Node.js,然后适当的回调将被添加到循环中执行。本文将进一步详细介绍这个话题。
时间循环解释
node . js开始执行时,会先初始化事件循环,处理提供的输入脚本(或者放入REPL,本文档不涉及)。这将执行异步API调用,调度定时器,或者调用process.nextTick(),然后开始处理事件循环。
下图显示了事件循环执行顺序的简单概述。
计时器
待定的回调
闲着,准备
来袭:
民意测验的人脉,
数据等。
检查
关闭回调
每一个盒子代表着事件循环的一个阶段
每个阶段都有一个FIFO队列回调,但是每个阶段都以自己的方式执行。一般来说,当事件循环进入一个阶段时,它会执行当前阶段的任何操作,并开始执行当前阶段队列中的回调,直到队列被完全消耗或队列中的最大数据被执行完。当队列用尽或达到最大数量时,事件循环将移动到下一阶段。
阶段概述
timers这个阶段执行setTimeout()和setInterval()的回调pending callbacks。I/O回调被推迟到下一个循环迭代idle,prepare。使用poll仅在内部检索新的I/O事件。执行I/O相关回调(几乎所有相关回调,关闭回调,)checksetImmediate()会调用close callbacks在这个阶段关闭回调,例如:socket.on(close ,).在事件循环的每个过程中,Node.js检查它是否正在等待异步I/O和计时器
阶段详情
timer
计时器指定回调将被执行的临界点,而不是人们希望它被执行的时间。计时器将在指定的过去时间后尽快执行。但是,操作系统调度或其他回调会延迟它的执行。
从技术上讲,轮询阶段决定了何时执行回调。
例如,您设置了一个计时器,它将在100毫秒后执行,但是您的脚本异步读取一个文件需要95毫秒。
const fs=require( fs );
函数someAsyncOperation(回调){
//假设这需要95毫秒才能完成
fs.readFile(/path/to/file ,回调);
}
const time out scheduled=date . now();
setTimeout(()={
const delay=date . now()-time out scheduled;
console . log(` { delay }毫秒后,我已被安排`);
}, 100);
//执行需要95毫秒才能完成的someAsyncOperation
someasyncooperation(()={
const start callback=date . now();
//做一些需要10毫秒的事情.
while(date . now()-start callback 10){
//什么都不做
}
});当事件循环进入轮询阶段时,它是一个空队列,(fs.readFile()尚未完成),因此它将等待剩余的毫秒,直到达到最快的计时器阈值。95 ms后,fs.readFile()完成读取文件,完成将其添加到轮询阶段并执行它需要10 ms。当回调完成时,队列中没有要执行的回调,事件循环返回到计时器阶段。在本例中,您将看到定时器在执行前延迟了105 ms。
为了防止轮询阶段阻塞事件循环,libuv(实现事件循环和平台上所有异步行为的C语言库)也在轮询阶段设置了一个最大值,以停止轮换训练更多的事件。
pending callbacks
此阶段执行某些系统操作的回调,如TCP错误类型。例如,如果TCP socket在尝试连接时收到ECONNREFUSED,某些*nix系统希望等待报告错误。这将在挂起的回调阶段排队等待执行。
poll
轮询阶段有两个主要功能
计算I/O阻塞的时间,并执行轮询队列中的事件。当事件循环进入轮询阶段并且没有计时器时,会发生以下两件事
如果轮询队列不为空,事件循环将同步迭代执行每个回调,直到执行完所有回调,或者达到系统的硬限制。如果轮询队列为空,将会发生以下两种情况。如果是setImmediate的回调,事件循环将结束轮询阶段,进入检查阶段执行回调。如果不是setImmediate,事件循环将等待回调被添加到队列中,然后立即执行。一旦轮询队列为空,事件循环将检测计时器是否到了,如果是,事件循环将到达计时器阶段以执行计时器回调。
check
此阶段允许人们在轮询阶段完成后立即执行回调。如果轮询阶段变得空闲,并且脚本已经用setImmediate()排队,则事件循环可能会继续到检查阶段,而不是等待。
SetImmediate()实际上是一个特殊的计时器,在事件周期的一个单独阶段运行。它使用libuv API来调度在轮询阶段完成后执行的回调。
通常,随着代码的执行,事件循环将最终到达轮询阶段,该阶段将等待传入的连接、请求等。但是,如果使用setImmediate()调度回调,并且轮询阶段变得空闲,它将结束并继续检查阶段,而不是等待轮询事件。
close callbacks
如果一个套接字或操作突然关闭(如socket.destroy()),关闭事件将被发送到此阶段,否则将通过process.nextTick()发送。
setImmediate() VS setTimeout()
setImmediate()和setTimeout()类似,但不同的行为取决于何时调用它们。
一旦轮询阶段结束,SetTimmediate()将被执行。setTimeout()将在短时间后执行。每个回调的执行顺序取决于调用它们的上下文。如果同时调用同一个模块,时间将受到进程性能的限制(这也会受到运行在这台机器上的其他应用程序的影响)
例如,如果我们不在I/O中运行以下脚本,尽管它受到进程性能的影响,但我们无法确定这两个计时器的执行顺序:
//timeout_vs_immediate.js
setTimeout(()={
console.log(timeout )。
}, 0);
setImmediate(()={
console . log(“immediate”);
});$ node timeout_vs_immediate.js
超时
马上
$ node timeout_vs_immediate.js
马上
但是,如果您进入I/O循环,立即回调将总是首先执行
//timeout_vs_immediate.js
const fs=require( fs );
fs.readFile(__filename,()={
setTimeout(()={
console.log(timeout )。
}, 0);
setImmediate(()={
console . log(“immediate”);
});
});$ node timeout_vs_immediate.js
马上
超时
$ node timeout_vs_immediate.js
马上
TimeTimeTimeImmediate相对于setTimeout的优势在于,timeoutsetImmediate总是在I/O中的任何计时器之前执行,而不管存在多少个计时器。
process.nextTick()
虽然process.nextTick()是异步API的一部分,但您可能已经注意到它没有出现在图中。这是因为process.nextTick()不是事件循环技术的一部分。相反,nextTickQueue将在当前操作完成后执行,而不考虑事件循环的当前阶段。这里,操作被定义为来自底层C/C处理器的转换,并处理需要执行的JavaScript。
根据图表,可以在任何阶段调用process.nextTick()。在事件循环继续执行之前,将执行传递给process.nextTick()的所有回调。这将导致一些不好的情况,因为它允许您递归地调用process . nexttick()‘饿死’您的I/O,这将阻止事件循环进入轮询阶段。
为什么这会被允许
为什么Node.js会收录这种情况?因为Node.js的设计思想是一个API应该总是异步的,即使它不是必须的,看看下面的片段。
函数apiCall(arg,callback) {
if (typeof arg!==string )
返回process.nextTick(
回拨,
new TypeError(“参数应为字符串”)
);
}会对片段进行参数检查,如果不正确,会将错误传递给回调。API最近进行了更新,允许将参数传递给process.nextTick(),这允许它接受回调后传递的任何参数作为回调的参数进行传播,因此您不必嵌套函数。
我们所做的是将错误返回给用户,但前提是我们允许用户代码的其余部分执行。使用process.nextTick(),我们保证apiCall()总是在剩余的用户代码之后、允许事件循环继续之前运行其回调。为了实现这一点,允许JS调用栈扩展,然后立即执行提供的回调。这允许人们在不到达RangeError的情况下对process.nextTick()进行递归调用:从v8开始超过了最大调用堆栈大小。
更多关于node的信息,请访问:nodejs教程!即上述事件周期是什么?解释Node.js中事件循环的细节,更多请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。