手机版

谈Node.js中的定时器

时间:2021-09-09 来源:互联网 编辑:宝哥软件园 浏览:

定时器在Node.js中的实现

正如上一篇博文中提到的,timer不是通过Node中新打开的线程实现的,而是直接在事件循环中实现的。下面通过几个JavaScript的定时器例子和Node的相关源代码来分析定时器功能是如何在Node中实现的。

JavaScript中定时器功能的特点

Node和浏览器中都有setTimeout和setInterval两个定时器功能,它们的工作特性基本相同,所以下面只是Node的一个例子。

我们知道,JavaScript中的计时器不同于计算机底部的定时中断。当中断到来时,当前执行的代码将被中断,并转而执行定时中断处理功能。当JavaScript的定时器到期时,如果当前执行线程没有正在执行的代码,就会执行相应的回调函数。如果当前有正在执行的代码,JavaScript引擎既不会中断当前代码执行回调,也不会启动新线程执行回调,而是在当前代码执行完毕后进行处理。

console.time('A')setTimeout(函数(){ console . time end(' A ');}, 100);var I=0;for(;我10万;I) {}执行上面的代码,可以看到最终输出的时间不是100ms左右,而是几秒钟。这表明在循环完成之前,计时回调函数没有执行,而是被推迟到循环结束。事实上,在JavaScript代码执行过程中,并不能处理所有的事件,在当前代码完成之前,也不能处理新的事件。这就是为什么浏览器在浏览器中运行耗时的JavaScript代码时会失去响应。为了应对这种情况,我们可以采用Yielding Processes的技巧,将耗时的代码分成块,每处理一个块就执行一次setTimeout,并规定短时间后处理下一个块。在这个空闲时间,浏览器/节点可以处理排队的事件。

补充信息

高级定时器和产生过程在第22章JavaScript高级编程高级技巧第三版中有详细讨论。

定时器在节点中的实现

uv_loop_t类型的Libuv初始化

最后一篇博文提到Node会调用libuv的uv_run函数启动default_loop_ptr进行事件调度,default_loop_ptr指向uv_loop_t类型default_loop_struct的一个变量。当节点启动时,将调用uv_loop_init(默认_ loop _ struct)来初始化节点。uv _ loop _ init的函数摘录如下:

int uv _ loop _ init(uv _ loop _ t * loop){ 0.循环时间=0;uv_update_time(循环);}您可以看到loop的time字段首先被赋值为0,然后调用uv_update_time函数,该函数会将最新的计数时间赋给loop.time

初始化后,default_loop_struct.time有一个初始值,与时间相关的操作将与该值进行比较,以确定是否调用相应的回调函数。

libuv的事件调度核心

前面提到的uv_run函数是libuv库实现事件循环的核心部分,下面是它的流程图:

以下是与定时器相关的上述逻辑的简要描述:

更新当前循环的时间字段,在当前循环概念下标记“现在”;

检查循环是否是活的,也就是检查循环中是否有需要处理的任务(处理程序/请求),如果没有,就不需要循环;检查已注册的定时器,如果定时器中指定的时间落后于当前时间,则表示定时器已经到达,因此执行其对应的回调函数;执行一次输入/输出轮询(即阻塞线程并等待输入/输出事件发生)。如果下一个定时器到期时没有I/O完成,停止等待,执行下一个定时器的回调。

如果发生I/O事件,执行相应的回调;由于计时器可能会在回调期间再次到期,请再次检查计时器并执行回调。(其实,(4。)这就比较复杂了,不仅仅是一步到位的操作。此描述仅关注定时器的实现,不涉及其他细节。)节点将调用uv_run,直到循环不再活动。

节点中的计时器包装和计时器

节点中有一个TimerWrap类,在节点内部注册为timer_wrap模块。

在Node _ module _ context _ aware _ builtin(timer _ wrap,Node :3360 TimerWrap 33603360 initialize)中,timer wrap类基本上是uv_timer_t的直接封装,Node _ module _ context _ aware _ builtin是Node用来注册内置模块的宏。

这一步之后,JavaScript就可以让这个模块进行操作了。文件src/lib/timers.js将timer_wrap的函数封装在JavaScript中,导出. settimeout、exports.setinterval、exports.setimmediate等函数。

节点启动和全局初始化

上一篇文章提到,当Node启动时,它将加载执行环境LoadEnvironment(env)。这个函数中非常重要的一步是加载src/node.js并执行它。src/node.js将加载指定的模块并初始化全局和进程。当然,像setTimeout这样的函数也将通过src/node.js绑定到全局对象

以上就是本文的全部内容,希望大家喜欢。

版权声明:谈Node.js中的定时器是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。