【第2章 Node.js基础】2.5 Node.js 的定时器

定时器timers 模块对外暴露一个全局的API用于调度在某个时段调用的函数因为定时器函数是全局变量,所以不需要加载timers 模块来使用它。Node.s 的定时器函敬实现了与 Web 浏览器提供的定时器 API 类似的 AP,但是它们使用了不同的内部实现机制,Nodeis 的定时器函数是基于 Node.s 事件循环构建的。

设置定时器

Node.js 中的定时器在一段时间后会调用给定的函数。何时调用定时器函数取决于用来创建定时器的方法及Node.is 事件循环正在执行的其他工作。

1, 一次性定时器

基本用法:

setTimeout(callback,delay[,...argsl)

这个方法用于延迟一个函数的执行时间,在到达指定的时间点执行该函数,并且只执行一次。其中参数 callback 用于指定要调用的回调函数,delay 设置调用回调函数之前等待的毫秒数,args 设置调用回调函数时传入的可选参数。它返回 Timeout 对象的ID,该D 可以传递给 clearTimeOut0)以取消该定时器。例如,下面的代码将在 1秒后输出提示信息,之后定时器就不再起作用。

setTimeout(function()
	console.log('我是一个一次性的定时器');
},1000);

定时器可能不会精确地在指定的时刻调用回调函数。Node.js 不保证回调被触发的确切时间,也不保证它们的顺序。回调函数会尽可能接近指定的时间,并在该时间点被调用。

2.周期性定时器

基本用法:

setInterval(callback, delay[,...argsl)

这个方法用于以指定的时间间隔周期性地执行回调函数,其参数和返回值同上述 setTimeout0)方法的参数和返回值。

例如,下面的代码将在 1 秒之后输出提示信息,之后定时器每隔 1 秒就重复输出提示信息,除非使用clearlnterval( )方法取消该定时器,或者终止程序。

setInterval (function(){
	console.log('我是一个周期性的定时器');
},1000);

3.即时定时器

基本用法:

setImmediate(callback[...args])

这个方法用于在 I/O 事件的回调之后立即执行回调函数,其比上述 setTimeout0方法少了一个 delay参数,返回的是Immediate 对象。

这是一个即时定时器,该方法并不会立即执行回调函数,而是在事件轮询之后执行函数,为了防止轮询阻塞,在每轮循环中仅执行链表中的一个回调函数。当程序多次调用 setlmmediate0)方法时,由该参数指定的回调函数将按照创建它们的顺序排队等待执行。每次事件循环迭代都会处理整个回调队列。如果即时定时器通过正在执行的回调加入队列,则要等到下一次事件循环迭代时才会被触发。

取消定时器

上述 setTimeout( )、setlnterval( )和 setlmmediate( )方法各自返回表示所设置的定时器的对象,这些对象可以用来取消定时器并防止该定时器触发,分别用 cearTimeout( )、cearinterval( )和clearlmmediate( )方法取消相应定时器。

例如,以下代码使用 setinterval( )方法设置周期性定时器后,使用clearinterval( )方法取消定时期

var testInterval=setInterval(testFunc,2000);
clearInterval(testInterval);

Timeout 和 Immediate 类

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 对象。

setImmediate() 方法和 setTimeout() 方法

与 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() 方法不允许嵌套调用,避免了无限递归的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

usp1994

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值