node中定时器, process.nextTick(), setImediate()的区别与联系

时间:2023-03-09 19:11:34
node中定时器, process.nextTick(), setImediate()的区别与联系

1.定时器

  setTimeout()和setInterval()与浏览器中的API是一致的,定时器的问题在于,他并非精确的(在容忍范围内)。尽管事件循环十分快,但是如果某一次循环占用的时间较多,那么下次循环时,他也许已经超时很久了。比如通过setTimeout()设定一个任务在10毫秒后执行,但是在9毫秒后,有一个任务占用了5毫秒的cpu时间片,再次轮到定时器执行时,时间就已经过期4毫秒。

2.process.nextTick()

  在未了解process.nextTick()之前,很多人也许为了立即异步执行一个任务,会这样调用setTimeout()来达到所需的效果:

  setTimeout(function () {
//code
}, 0);

  由于事件循环自身的特点,定时器的精确度不够。而事实上,采用定时器需要动用红黑树,创建定时器对象和迭代等操作,而setTimeout(fn, 0)的方式较为浪费性能。实际上process.nextTick()方法的操作相对较为轻量。

  每次调用process.nextTick()方法,只会将回调函数放入队列中,在下轮tick时取出执行,定时器中采用红黑树的操作时间复杂度为O(lg(n)),nextTick()的时间复杂度为O(1),很明显,nextTick()更加高效。

3.setImmediate()

  setImmediate()方法与process.nextTicl()方法十分类似,都是将回调函数延迟执行。在node V0.9.1之前,setImmediate()还没有实现,那时候实现类似的功能主要是通过process,nextTick()来完成。

4.nextTick()和setImmediate()区别与联系

  process.nextTick()中的回调函数执行的优先级要高于setImmediate().这里的原因在于事件循环对观察者的检查是有先后顺序的,process.nextTick()属于idle观察者,setImmediate()属于check观察者。在每一个轮循环检查中,idle观察者先于I/O观察者,I/O观察者先于check观察者。  

  在具体实现上,process.nextTick()的回调函数保存在一个数组中,setImmediate()的结果则是保存在链表中。在行为上,process.nextTick()在每轮循环中会将该数组中的回调函数全部执行完,而setImmediate()在每轮循环中执行链表中的一个回调函数。下面是例子:

//加入两个nextTick()的回调函数
process.nextTick(function () {
console.log('nextTick延迟执行1');
});
process.nextTick(function () {
console.log('nextTick延迟执行2');
})
//加入两个setImmediate()的回调函数
setImmediate(function () {
console.log('setImmediate延迟执行1');
//进入下次循环
process.nextTick(function () {
console.log("强势插入!!");
});
});
setImmediate(function () {
console.log("setImmediate延迟执行2");
});
console.log("正常执行");

其执行结果如下:

正常执行

nextTick延迟执行1

nextTick延迟执行2

setImmediate延迟执行1

setImmediate延迟执行2

强势插入!!