Scheduling Timers
一、setImmediate(callback[, ...args])
1.1 认识
setImmediate(callback[, ...args]) 在 I/O
事件的回调之后调度 callback
的“立即”执行。当多次调用 setImmediate()
时,则 callback
函数会按照它们的创建顺序排队执行。 每次事件循环迭代都会处理整个回调队列。 如果立即定时器从正在执行的回调中排队,则直到下一次事件循环迭代才会触发该定时器。
1.2 语法
const immediateID = setImmediate(()=>{},arg1,arg2,……,argn);
- callback: 在本轮
Node.js
事件循环结束时调用的函数 - ...args: 调用
callback
时要传入的可选参数。 - immediateID: 用于
clearImmediate()
二、setInterval(callback[, delay[, ...args]])
2.1 认识
setInterval(callback[, delay[, ...args]]) 每 delay
毫秒调度重复执行 callback
。
2.2 语法
const intervalID = setInterval(()=>{},delay,arg1,arg2,……,argn);
- callback: 当定时器结束时调用的函数。
- delay: 调用
callback
之前等待的毫秒数。 默认值: 1。当delay
大于2147483647
或小于1
时,则delay
将设置为1
。 非整数延迟被截断为整数。 - arg1,arg2,……,argn: 调用 callback 时要传入的可选参数。
- intervalID: 用于
clearInterval()
三、setTimeout(callback[, delay[, ...args]])
3.1 认识
setTimeout(callback[, delay[, ...args]]) delay
毫秒后调度单次的 callback
的执行。
3.2 语法
const timeoutID = setTimeout(()=>{},delay,arg1,arg2,……,argn);
- callback: 当定时器结束时调用的函数。
- delay: 调用
callback
之前等待的毫秒数。 默认值: 1。当delay
大于2147483647
或小于1
时,则delay
将设置为1
。 非整数延迟被截断为整数。 - arg1,arg2,……,argn: 调用 callback 时要传入的可选参数。
- intervalID: 用于
clearInterval()
3.3 对比
一、setImmediate()
与 setTimeout()
对比
-
针对调用时机:
setImmediate()
和setTimeout()
很类似,但是基于被调用的时机,他们也有不同表现:setImmediate()
在当前poll
阶段完成后check
阶段执行脚本setTimeout()
在最小阈值(ms 单位)过后运行脚本。poll
阶段为空闲时,且设定时间到达后执行,但它在timer
阶段执行
-
针对调用顺序: 执行计时器的顺序将根据调用它们的上下文而异
-
如果二者都从主模块内调用: 则计时器将受进程性能的约束(这可能会受到计算机上其他正在运行应用程序的影响),执行两个计时器的顺序是非确定性的
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
}); -
如果二者都在
I/O
循环内调用:setImmediate
总是被优先调用const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
}); -
使用
setImmediate()
相对于setTimeout()
的主要优势: 如果setImmediate()
是在I/O
周期内被调度的,那它将会在其中任何的定时器之前执行,跟这里存在多少个定时器无关
-
二、process.nextTick()
与 setImmediate()
对比
-
从执行时机上来看:
process.nextTick()
在同一个阶段立即执行。setImmediate()
在事件循环的接下来的迭代或 'tick' 上触发。
实质上,这两个名称应该交换,因为
process.nextTick()
比setImmediate()
触发得更快,但这是过去遗留问题,因此不太可能改变。我们建议开发人员在所有情况下都使用setImmediate()
,因为它更容易理解。 -
从事件循环阶段来看:
process.nextTick
:process.nextTick
从技术上讲不是事件循环的一部分。process.nextTick()
方法将callback
添加到next tick
队列。 一旦当前事件轮询队列的任务全部完成,在next tick
队列中的所有callbacks
会被依次调用,并且优先于其他microtask
执行setImmediate
-
从设计理念的角度来看:
process.nextTick
:process.nextTick
可以保证回调在其余代码(比如说 初始化所有的变量、函数)之后、事件循环之前执行回调函数。为了实现这一点,JS 调用栈被允许展开,然后立即执行提供的回调,允许进行递归调用process.nextTick()
,而不触碰RangeError
: 超过 V8 的最大调用堆栈大小 限制。setImmediate
:
-
从使用场景、存在意义来看(为什么要使用):
-
process.nextTick
:- 允许用户处理错误,清理任何不需要的资源,或者在事件循环继续之前重试请求
- 有时有让回调在栈展开后,但在事件循环继续之前运行的必要
-
setImmediate
:
-