nodeJS笔记 | 定时器

本文详细解析了Node.js中的四种定时器:setTimeout(), setInterval(), setImmediate()和process.nextTick()的工作原理,包括它们的异同、如何使用以及如何取消定时器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

仅做笔记分享,如有错误请高手指出

Node的四个定时器:setTimeout(),setInterval(),setImmediate(),process.nextTick()

1.setTimeout()

一次性定时器setTimeout(),

官方中文文档:
setTimeout()
用于设定在指定的毫秒数之后执行某些代码. 这个函数和浏览器中的JavaScript API window.setTimeout() 类似, 然而Node.js的 setTimeout() 不能传入字符串形式的代码.
setTimeout() 的接收的第一个参数是要延迟执行的回调, 第二个参数是要延迟的毫秒数. 还可以传入更多的参数, 多出来的这些参数会被传入回调函数., 例如:

function myFunc(arg) {
      console.log(`arg was => ${arg}`);
    }
setTimeout(myFunc, 1500, 'funky');
    1
    2
    3
    4
    5

由于使用了 setTimeout(), 上例中的 myFunc() 将会在1500ms之后尽可能早地执行.

不能够依赖设定的超时间隔来实现在精确的毫秒数之后就执行某些代码.
这是因为其他正在执行的阻塞或持续占用事件循环的代码会导致所设定函数推迟执行. 唯一能保证的是所设定的函数不会在设定的超时间隔之前执行.

setTimeout() 返回一个用来引用所设置的超时任务 Timeout 对象. 这个对象可以用来取消超时任务(见下方的
clearTimeout()), 也可以改变执行任务时的行为(键下方的 unref()).

setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行结束,主线程才会去执行它指定的回调函数。若当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。

timer0()=>{
  console.log('约一秒后打印timer0');
}
setTimeout(timer0,1000);

2.setInterval()

周期性定时器setInterval()

官方中文文档:
如果需要定期多次执行一些代码, 用 setInterval() 可以做到. setInterval() 接收一个回调函数作为第一个参数, 接收一个毫秒数的时间间隔作为第二个参数, 然后每过时间间隔就执行一次回调函数. 就像 setTimeout() 一样, 额外的参数会被传入回调函数, 而且延迟时间也和 setTimeout() 一样无法保证精确, 因为可能有其他操作持续占用事件循环, 因此这个时间间隔应认为是近似间隔.

timer1()=>{
	consloe.log('约每一秒打印1次')
}
setInterval(timer1,1000)

3.setImmediate()

官方中文文档:
setImmedate() 可以设置要在本次事件循环结束时执行的代码. 这些代码将会在本次事件循环的所有I/O操作之后, 且在下次事件循环的所有定时器之前执行. 这种代码的执行可以认为是”在这之后”立刻发生的, 也就是说所有紧随 setImmedate() 之后的函数调用会在 setImmedate() 所设定的回调函数之前执行.
setImmedate() 的第一个参数是即将被执行的回调函数, 所有之后的参数都将被传入回调函数

console.log(1)
setImmediate(()=>{
  console.log(3);
});
console.log(2);
//1
//2
//3

setImmedate() 返回一个用于取消该任务的 Immedate 对象(见下方 clearImmediate()).

注意: 不要把 setImmedate() 和 process.nextTick() 搞混了. 它们之间有几点主要的差异:

process.nextTick() 会在所有 setImmedate() 设定的回调和所有I/O之前执行

process.nextTick() 是不可清除的, 也就是说一旦使用 process.nextTick() 设置了回调, 就无法再取消了.

4.

官方中文文档:
process.nextTick()方法将 callback 添加到"next tick 队列"。 一旦当前事件轮询队列的任务全部完成,在next tick队列中的所有callbacks会被依次调用。

这种方式不是setTimeout(fn, 0)的别名。它更加有效率。事件轮询随后的ticks 调用,会在任何I/O事件(包括定时器)之前运行。

console.log(1);
process.nextTick(() => {
  console.log(3);
});
console.log(2);
// 1
// 2
// 3

此方法在开发如下API时非常重要:在对象构造好但还没有任何I/O发生之前,想给用户机会来指定某些事件处理器。

function MyThing(options) {
  this.setupOptions(options);

  process.nextTick(() => {
    this.startDoingStuff();
  });
}

const thing = new MyThing();
thing.getReadyForStuff();

// thing.startDoingStuff() 调用是在现在,不是在之前

对于100%同步或100%异步的API,此方法也非常重要。考虑如下例子:

// 警告!不要使用!严重不安全隐患!
function maybeSync(arg, cb) {
  if (arg) {
    cb();
    return;
  }

  fs.stat('file', cb);
}

在如下场景中这个API是危险的:

const maybeTrue = Math.random() > 0.5;

maybeSync(maybeTrue, () => {
  foo();
});

bar();

如下方式要更好一些:

function definitelyAsync(arg, cb) {
  if (arg) {
    process.nextTick(cb);
    return;
  }

  fs.stat('file', cb);
}

注意: 每次事件轮询后,在额外的I/O执行前,next tick队列都会优先执行。 递归调用nextTick callbacks 会阻塞任何I/O操作,就像一个while(true); 循环一样。

注意:

  1. Node规定process.nextTick()和Promise的回调函数是追加在本轮循环,而setTimeout()、setInterval()、setImmediate()是追加再次轮循环中的
  2. process.nextTick()是异步事件中最快执行的
  3. Promise的回调函数追加在process.nextTick()事件的微任务中,也被划为本轮循环

5.清除定时器

如果需要取消 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 对象提供了 unref() 和 ref() 两个方法用以增强该对象的行为. 如果有一个使用 set 函数设置的 Timeout 对象, unref() 方法可以在该对象上被调用. 这会稍微改变对象的行为: 如果该 Timeout 是最后要执行的代码, 则不去调用该 Timeout. 此时的 Timeout 对象不会保持进程为活动状态, 会等待被调用.

以此类推, 对于一个调用过 unref() 的 Timeout 对象, 可以调用它的 ref() 对象来撤销 unref() 所导致的改变, 这会使该 Timeout 对象稍后又可以被调用. 然而要明白的是, 由于性能原因, 这种做法无法精确地恢复到最初的行为. 例子如下:

const timerObj = setTimeout(() => {
  console.log('will i run?');
});

//如果不加修改,本声明将保留上述内容

//运行超时,因为只有超时

//阻止程序退出的东西
timerObj.unref();

//我们可以通过调用ref()来恢复它的生命

//立即
setImmediate(() => {
  timerObj.ref();
});

【高手文章】:
NodeJS官方文档中文版之《Node.js中的定时器》:https://blog.youkuaiyun.com/juhaotian/article/details/79009221
Node定时器详解:https://blog.youkuaiyun.com/zhagnqian_96/article/details/79848118?utm_source=blogxgwz3
setTimeout和setImmediate以及process.nextTick的区别:https://www.cnblogs.com/cdwp8/p/4065846.html
node中定时器, process.nextTick(), setImediate()的区别与联系:https://www.cnblogs.com/yonglin/p/7857804.html

### Vue 3 重要项目事件笔记 #### 组件通信方式的变化 Vue 3 中移除了事件总线,推荐使用 `mitt` 来替代。这使得跨组件通信更加简洁高效[^1]。 ```typescript // src/utils/emitter.ts import mitt from 'mitt'; const emitter = mitt(); export default emitter; ``` 通过上述代码创建了一个全局事件中心实例,在不同组件间可以方便地进行消息传递: - 使用 `emitter.on(eventName, callback)` 订阅特定名称的事件; - 调用 `emitter.emit(eventName[, args...])` 发布指定类型的事件给监听者处理; - 执行 `emitter.off([eventName][, handler])` 或 `emitter.all.clear()` 可取消订阅单个/全部事件。 #### 状态管理库升级 原有的 Vuex 库已被 Pinia 替代作为官方首选的状态管理模式。Pinia 提供更灵活易懂API设计以及更好的 TypeScript 支持特性。 #### v-model 的改进 `.sync` 修饰符的功能已经被整合进了增强版 `v-model` 内部逻辑里,简化了父子组件之间双向绑定的操作流程。 #### 新增 setup 函数 Composition API 是 Vue 3 推出的一项重大革新,其中核心部分就是引入了 `setup` 配置选项。它允许开发者在一个地方集中定义响应式变量、计算属性、侦听器等功能模块,从而提高代码可读性和维护性[^2]。 ```javascript <script> import { ref, computed } from 'vue'; export default { props: ['title'], setup(props) { const count = ref(0); const doubleCount = computed(() => count.value * 2); return { count, increment: () => (count.value += 1), decrement: () => (count.value -= 1), doubledTitle: computed(() => `${props.title}-${doubleCount}`) }; } }; </script> ``` #### 实现防抖功能 利用自定义 Ref 和定时器机制来实现简单的防抖效果,适用于输入框自动补全等场景下减少不必要的请求次数[^4]。 ```typescript // useDebounceRef.ts import { customRef } from "vue"; function debounce<T>(initValue:T, delay:number){ let timeoutId: NodeJS.Timeout | null; return customRef((track, trigger)=>{ return{ get(){ track(); return initValue; }, set(newValue){ if(timeoutId !== null){ clearTimeout(timeoutId); } timeoutId = setTimeout(()=>{ initValue = newValue; trigger(); timeoutId = null; },delay); } } }); } export default debounce; ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值