定时器timers 模块对外暴露一个全局的API用于调度在某个时段调用的函数因为定时器函数是全局变量,所以不需要加载timers 模块来使用它。Node.s 的定时器函敬实现了与 Web 浏览器提供的定时器 API 类似的 AP,但是它们使用了不同的内部实现机制,Nodeis 的定时器函数是基于 Node.s 事件循环构建的。
Node.js 中的定时器在一段时间后会调用给定的函数。何时调用定时器函数取决于用来创建定时器的方法及Node.is 事件循环正在执行的其他工作。
基本用法:
setTimeout(callback,delay[,...argsl)
这个方法用于延迟一个函数的执行时间,在到达指定的时间点执行该函数,并且只执行一次。其中参数 callback 用于指定要调用的回调函数,delay 设置调用回调函数之前等待的毫秒数,args 设置调用回调函数时传入的可选参数。它返回 Timeout 对象的ID,该D 可以传递给 clearTimeOut0)以取消该定时器。例如,下面的代码将在 1秒后输出提示信息,之后定时器就不再起作用。
setTimeout(function()
console.log('我是一个一次性的定时器');
},1000);
定时器可能不会精确地在指定的时刻调用回调函数。Node.js 不保证回调被触发的确切时间,也不保证它们的顺序。回调函数会尽可能接近指定的时间,并在该时间点被调用。
基本用法:
setInterval(callback, delay[,...argsl)
这个方法用于以指定的时间间隔周期性地执行回调函数,其参数和返回值同上述 setTimeout0)方法的参数和返回值。
例如,下面的代码将在 1 秒之后输出提示信息,之后定时器每隔 1 秒就重复输出提示信息,除非使用clearlnterval( )方法取消该定时器,或者终止程序。
setInterval (function(){
console.log('我是一个周期性的定时器');
},1000);
基本用法:
setImmediate(callback[, ...args])
这个方法用于在 I/O 事件的回调之后立即执行回调函数,其比上述 setTimeout0方法少了一个 delay参数,返回的是Immediate 对象。
这是一个即时定时器,该方法并不会立即执行回调函数,而是在事件轮询之后执行函数,为了防止轮询阻塞,在每轮循环中仅执行链表中的一个回调函数。当程序多次调用 setlmmediate0)方法时,由该参数指定的回调函数将按照创建它们的顺序排队等待执行。每次事件循环迭代都会处理整个回调队列。如果即时定时器通过正在执行的回调加入队列,则要等到下一次事件循环迭代时才会被触发。
上述 setTimeout( )、setlnterval( )和 setlmmediate( )方法各自返回表示所设置的定时器的对象,这些对象可以用来取消定时器并防止该定时器触发,分别用 cearTimeout( )、cearinterval( )和clearlmmediate( )方法取消相应定时器。
例如,以下代码使用 setinterval( )方法设置周期性定时器后,使用clearinterval( )方法取消定时期
var testInterval=setInterval(testFunc,2000);
clearInterval(testInterval);
Node.js 内置了两个与定时器相关的类:Timeout 和 Immediate。可以使用 setTimeout() 或 setInterval() 方法创建 Timeout 对象,并使用 clearTimeout() 或 clearInterval() 方法取消定时器。默认情况下,当设置了定时器后,Node.js 事件循环将继续执行。
Timeout 对象提供了 timeout.ref() 和 timeout.unref() 方法,用于控制定时器的默认行为。ref() 方法将定时器添加到事件循环中,使其保持活动状态,而 unref() 方法将定时器从事件循环中移除,使其不再影响事件循环的执行。
Immediate 对象可以使用 setImmediate() 方法创建,并使用 clearImmediate() 方法取消即时定时器。默认情况下,当设置了即时定时器后,Node.js 事件循环将继续执行。
Immediate 对象提供了 immediate.ref() 和 immediate.unref() 方法,用于控制即时定时器的默认行为。ref() 方法将即时定时器添加到事件循环中,使其保持活动状态,而 unref() 方法将即时定时器从事件循环中移除,使其不再影响事件循环的执行。
需要注意的是,在 setTimeout() 或 setInterval() 方法中,this 关键字在 JavaScript 中指向 window 对象,而在 Node.js 中指向 Timeout 对象。
与 setTimeout() 方法相比,setImmediate() 方法的主要优点是,无论在一个 I/O 周期内有多少个定时器,setImmediate() 方法都会在当前事件循环迭代的末尾执行。
方法 | setImmediate() | setTimeout() |
---|---|---|
执行时机 | 在事件循环的下一个迭代中立即执行 | 在指定的延迟时间后执行 |
执行顺序 | 在当前事件循环迭代的末尾执行 | 在当前事件循环迭代的末尾执行 |
延迟时间 | 无延迟,立即执行 | 可以设置延迟时间 |
取消定时器 | 使用 clearImmediate() 方法 | 使用 clearTimeout() 方法 |
默认行为 | 在活动状态下,不会阻塞事件循环 | 在活动状态下,不会阻塞事件循环 |
控制默认行为 | 使用 immediate.ref() 和 immediate.unref() 方法 | 使用 timeout.ref() 和 timeout.unref() 方法 |
this 关键字 | 指向 Immediate 对象 | 指向 Timeout 对象 |
一个IO周期(即主模块)内执行两个定时器函数(timeout_vs immediate1.js)
setTimeout(() => {
console.log('一次性');
}, 0);
setImmediate(() => {
console.log('即时性');
});
在这个例子中,setTimeout() 设置了一个延迟时间为 0 的定时器,而 setImmediate() 设置了一个即时定时器。
在一个 I/O 周期内调用这两个方法时,它们的执行顺序是不确定的,因为它们都是在当前事件循环迭代的末尾执行。具体执行顺序可能受到事件循环的状态和其他异步操作的影响。
执行结果:
PS D:\WuWorkSpace\code\NodejsProject\nodejs实战学习\【第2章 Node.js基础】\2.5计时器> node .\timeout_vs_immediate.js
即时性
一次性
PS D:\WuWorkSpace\code\NodejsProject\nodejs实战学习\【第2章 Node.js基础】\2.5计时器> node .\timeout_vs_immediate.js
一次性
即时性
但是,如果将这两个函数放入一个I/O 循环内,那么setlmmediate 总是被优先调用
同一个I/O 循环内执行两个定时器函数(timeout_vs immediate2.js)
const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('一次性');
}, 0);
setImmediate(() => {
console.log('即时性');
});
});
执行结果如下:
PS D:\WuWorkSpace\code\NodejsProject\nodejs实战学习\【第2章 Node.js基础】\2.5计时器> node '.\timeout_vs immediate2.js'
即时性
一次性
PS D:\WuWorkSpace\code\NodejsProject\nodejs实战学习\【第2章 Node.js基础】\2.5计时器> node '.\timeout_vs immediate2.js'
即时性
一次性
PS D:\WuWorkSpace\code\NodejsProject\nodejs实战学习\【第2章 Node.js基础】\2.5计时器> node '.\timeout_vs immediate2.js'
即时性
一次性
process.nextTick()
和 setImmediate()
process.nextTick()
和 setImmediate()
都是用于在 Node.js 中执行异步操作的方法,但它们之间有一些重要的区别。
下面是 process.nextTick()
和 setImmediate()
的对比:
方法 | process.nextTick() | setImmediate() |
---|---|---|
执行时机 | 在当前操作完成后,下一个事件循环迭代之前执行 | 在当前事件循环的末尾执行 |
执行顺序 | 在当前事件循环迭代中的最后执行 | 在当前事件循环迭代的末尾执行 |
优先级 | 高优先级,比其他异步操作(包括定时器)更早执行 | 低优先级,比其他异步操作(包括定时器)稍后执行 |
嵌套调用 | 允许嵌套调用,可以无限递归 | 不允许嵌套调用,避免无限递归 |
控制默认行为 | 无法控制默认行为 | 使用 immediate.ref() 和 immediate.unref() 控制默认行为 |
this 关键字 | 指向当前模块的 exports 对象 | 指向 Immediate 对象 |
总的来说,process.nextTick()
方法具有更高的优先级,它会在当前操作完成后立即执行,而不需要等待下一个事件循环迭代。这使得它在需要优先执行的情况下非常有用,例如在处理错误回调或需要立即更新状态的情况下。
相比之下,setImmediate()
方法在当前事件循环迭代的末尾执行,它的优先级较低。它适用于需要在当前事件循环迭代的末尾执行回调函数的情况,避免阻塞其他异步操作。
需要注意的是,process.nextTick()
方法允许嵌套调用,这意味着可以在回调函数中再次调用 process.nextTick()
,从而形成无限递归。而 setImmediate()
方法不允许嵌套调用,避免了无限递归的问题。