共计 3224 个字符,预计需要花费 9 分钟才能阅读完成。
Node.js 中的定时器
Node.js 中的 Timers 模块包含在一段时间后执行代码的函数,定时器不需要通过 require() 导入,因为所有方法都可以在全局范围内模拟浏览器 JavaScript API,要完全了解何时执行定时器功能,最好先阅读 Node.js 事件循环。
用 Node.js 控制时间连续性
Node.js API 提供了几种调度代码的方法,以便在当前时刻之后的某个时刻执行,下面的函数可能看起来很熟悉,因为它们在大多数浏览器中都可用,但 Node.js 实际上提供了这些方法的自己的实现,定时器与系统紧密集成,尽管 API 镜像了浏览器 API,但实现方面存在一些差异。
“我说的时候”执行 ~ setTimeout()
setTimeout() 可用于在指定的毫秒数后调度代码执行,此函数类似于浏览器 JavaScript API 中的 window.setTimeout(),但是无法传递一串代码来执行。
setTimeout() 接受一个函数作为第一个参数执行,毫秒延迟定义为一个数字作为第二个参数,还可以包括其他参数,并将这些参数传递给函数,这是一个例子:
function myFunc(arg) {
console.log(`arg was => ${arg}`);
}
setTimeout(myFunc, 1500, ‘funky’);
由于调用了 setTimeout(),上面的函数 myFunc() 将尽可能接近 1500 毫秒(或 1.5 秒)执行。
设置的超时间隔不能依赖于在该精确的毫秒数之后执行,这是因为阻塞或保留在事件循环上的其他执行代码将推迟执行超时,唯一的保证是超时不会比声明的超时间隔更早执行。
setTimeout() 返回一个 Timeout 对象,该对象可用于引用已设置的超时,此返回的对象可用于取消超时(请参阅下面的 clearTimeout())以及更改执行行为(请参阅下面的 unref())。
“在此之后”执行 ~ setImmediate()
setImmediate() 将在当前事件循环周期结束时执行代码,此代码将在当前事件循环中的任何 I / O 操作之后以及为下一个事件循环调度的任何计时器之前执行,这个代码执行可以被认为是“正好在此之后”,这意味着 setImmediate() 函数调用之后的任何代码都将在 setImmediate() 函数参数之前执行。
setImmediate() 的第一个参数将是要执行的函数,任何后续参数将在执行时传递给函数,这是一个例子:
console.log(‘before immediate’);
setImmediate((arg) => {
console.log(`executing immediate: ${arg}`);
}, ‘so immediate’);
console.log(‘after immediate’);
传递给 setImmediate() 的上述函数将在所有可运行代码执行后执行,控制台输出将为:
before immediate
after immediate
executing immediate: so immediate
setImmediate() 返回一个 Immediate 对象,可用于取消已调度的 immediate(请参阅下面的 clearImmediate())。
注意:不要混淆 setImmediate() 和 process.nextTick(),它们有一些主要的不同之处,第一个是 process.nextTick() 将在任何设置的 Immediate 之前以及任何调度的 I / O 之前运行,第二个是 process.nextTick() 是不可清除的,意思是一旦代码被安排用 process.nextTick() 执行,就无法停止执行,就像使用普通函数一样,请参阅本指南以更好地理解 process.nextTick() 的操作。
“无限循环”执行 ~ setInterval()
如果存在应该多次执行的代码块,则可以使用 setInterval() 来执行该代码,setInterval() 接受一个函数参数,它将以给定的毫秒延迟作为第二个参数运行无限次,就像 setTimeout() 一样,可以在延迟之外添加其他参数,并将这些参数传递给函数调用。也像 setTimeout() 一样,由于可能保留在事件循环上的操作,因此无法保证延迟,因此应将其视为近似延迟,见下面的例子:
function intervalFunc() {
console.log(‘Cant stop me now!’);
}
setInterval(intervalFunc, 1500);
在上面的例子中,intervalFunc() 大约每 1500 毫秒或 1.5 秒执行一次,直到它被停止为止(见下文)。
与 setTimeout() 一样,setInterval() 也返回一个 Timeout 对象,该对象可用于引用和修改已设置的间隔。
清除未来
如果需要取消 Timeout 或 Immediate 对象,可以做些什么?setTimeout()、setImmediate() 和 setInterval() 返回一个可用于引用设置 Timeout 或 Immediate 对象的计时器对象,通过将所述对象传递到相应的 clear 函数,将完全停止该对象的执行。相应的函数是 clearTimeout(),clearImmediate() 和 clearInterval(),请参阅下面的示例,了解每个示例:
const timeoutObj = setTimeout(() => {
console.log(‘timeout beyond time’);
}, 1500);
const immediateObj = setImmediate(() => {
console.log(‘immediately executing immediate’);
});
const intervalObj = setInterval(() => {
console.log(‘interviewing the interval’);
}, 500);
clearTimeout(timeoutObj);
clearImmediate(immediateObj);
clearInterval(intervalObj);
留下超时
请记住,setTimeout 和 setInterval 返回 Timeout 对象,Timeout 对象提供了两个函数,旨在使用 unref() 和 ref() 来增强 Timeout 行为。如果使用 set 函数调度 Timeout 对象,则可以在该对象上调用 unref(),这将稍微改变行为,如果它是要执行的最后一个代码,则不会调用 Timeout 对象,Timeout 对象不会使进程保持活动状态,等待执行。
以类似的方式,调用了 unref() 的 Timeout 对象可以通过在同一个 Timeout 对象上调用 ref() 来删除该行为,然后确保其执行。但请注意,出于性能原因,这并不能完全恢复初始行为,请参阅以下两个示例:
const timerObj = setTimeout(() => {
console.log(‘will i run?’);
});
// if left alone, this statement will keep the above
// timeout from running, since the timeout will be the only
// thing keeping the program from exiting
timerObj.unref();
// we can bring it back to life by calling ref() inside
// an immediate
setImmediate(() => {
timerObj.ref();
});
进一步了解事件循环
事件循环和计时器比本指南所涵盖的要多得多,要了解有关 Node.js 事件循环内部以及计时器在执行期间如何操作的更多信息,请查看此 Node.js 指南:Node.js 事件循环、定时器和 process.nextTick()。
上一篇:不要阻塞事件循环(或工作池)