← 返回题目列表

Node.js 定时器的 ref 和 unref 有什么作用?

中等 第 26 / 27 题 更新于 2026/07/29
Node.jsTimerrefunref

简化版

Node.js 定时器默认会让事件循环保持活跃,进程不会退出。调用 unref() 可以表示这个定时器不应该单独阻止进程退出;ref() 则恢复保活能力。它常用于后台心跳、超时兜底和非关键定时任务。

详细版

普通定时器会让 Node 进程继续运行。

const timer = setInterval(() => {
  console.log('heartbeat')
}, 10_000)

timer.unref()

unref() 后,如果进程里没有其他活跃任务,Node 可以退出,不会为了这个定时器硬撑着。面试要注意:unref() 不是取消定时器,定时器在进程仍活着时仍可能触发;取消要用 clearTimeoutclearInterval

完整版教学

一、Node 进程退出取决于事件循环是否还有活跃句柄

Node.js 不是代码执行完就一定退出。 只要事件循环里还有活跃句柄,比如 server、socket、定时器,进程就会继续运行。 定时器默认就是会保活的句柄。

setTimeout(() => {
  console.log('10 秒后执行')
}, 10_000)

上面代码即使没有其他任务,进程也会等 10 秒。 因为这个 timeout 仍然被认为是活跃工作。 这就是理解 ref/unref 的基础。

二、unref 表示不要为了它单独保活

timer.unref() 的含义是:如果事件循环里只剩这个定时器,不要为了它阻止进程退出。 它适合非关键后台任务。 进程还活着时,定时器仍会正常触发。

const timer = setTimeout(() => {
  console.log('兜底清理')
}, 30_000)

timer.unref()
操作是否取消定时器是否保活进程
默认定时器
unref()
ref()
clearTimeout()

这个表能防止一个常见误会:unref 不等于 clear。 它只影响进程退出判断。

三、ref 可以恢复保活

调用 unref() 后,如果业务又需要这个定时器保持进程,可以调用 ref()。 这在动态任务管理中偶尔有用。 不过日常更常见的是只对后台兜底 timer 调一次 unref()

const timer = setInterval(syncMetrics, 60_000)
timer.unref()

// 某些场景下重新要求保活
timer.ref()

如果一个 CLI 工具只为了上报指标设置了 interval,默认保活会导致命令迟迟不退出。 这类场景用 unref() 很合适。

四、超时兜底常搭配 unref

优雅停机、请求取消、任务超时都可能设置兜底定时器。 兜底定时器的目的不是让进程多活,而是在进程还活着时防止流程卡死。 所以经常会 unref()

const shutdownTimer = setTimeout(() => {
  console.error('shutdown timeout')
  process.exit(1)
}, 30_000)

shutdownTimer.unref()
有其他活跃任务 -> 到点触发兜底
没有其他活跃任务 -> 进程可直接退出

这样既有保险,又不让保险本身变成进程退出的阻碍。

五、服务端心跳和指标上报要谨慎使用

后台指标上报、健康心跳、缓存刷新常用 interval。 如果这些任务不是服务存活的必要条件,可以 unref。 但如果它们承担核心调度功能,就不能随意 unref。

任务是否适合 unref原因
CLI 指标上报适合不应阻止命令退出
停机超时兜底适合只是保险
核心任务调度不适合进程应为它保持运行
HTTP server不适用server 自身是活跃句柄

判断标准是:这个定时器是不是进程继续存在的理由。 如果不是,就可以考虑 unref()

六、排查进程不退出时要看活跃句柄

很多测试脚本卡住不退出,原因可能是未清理定时器、未关闭 server、数据库连接没断。 unref() 可以处理非关键定时器,但核心资源仍要显式关闭。

记忆钩子:clear 是取消闹钟,unref 是告诉 Node 别为了这个闹钟不睡觉。

面试里把这个比喻讲出来,再补事件循环活跃句柄,就很清楚。 不要把它和定时器清理混淆。

七、常见误区与追问

  • 误区:unref 会取消定时器。 它只是不让定时器单独保活进程,取消仍要用 clearTimeoutclearInterval
  • 误区:所有定时器都应该 unref。 核心调度任务需要保活进程,不能随便 unref。
  • 误区:进程不退出一定是 timer 问题。 server、socket、数据库连接、文件监听也会让事件循环保持活跃。
  • 追问:ref 有什么用? 它能恢复句柄保活能力,让定时器重新阻止进程退出。
  • 追问:优雅停机超时为什么常用 unref? 兜底 timer 不应成为唯一阻止进程退出的原因。
  • 追问:unref 后定时器还会执行吗? 如果进程因为其他活跃句柄仍在运行,到时间仍会执行。

八、加强记忆

ref/unref 题抓“进程保活”。定时器默认保活,unref 不取消任务,只是不让它单独拽住事件循环。CLI、兜底超时、非关键后台任务常用它;核心调度和服务资源要谨慎。