onCleanup 是 watchEffect 内置的清理函数,仅在副作用被覆盖或组件卸载前触发,用于安全中断异步操作;必须同步注册,否则报错;典型应用是结合 AbortController 取消请求并配合 cancelled 标记防状态污染。

onCleanup 的作用和触发时机
onCleanup 是 watchEffect 内置的清理注册函数,不是每次 effect 执行完都运行,而是在当前副作用即将被覆盖(比如依赖变化触发重跑)或组件卸载前,自动调用上一次注册的清理逻辑。它专门用于处理“已启动但尚未完成、却已过期”的异步操作,比如正在发送的请求、未到期的定时器、已绑定的事件监听器。
必须同步注册,否则会报错
onCleanup 只能在 watchEffect 回调的同步执行阶段调用。一旦进入 await、setTimeout、Promise.then 等异步上下文,Vue 就无法将清理函数绑定到当前副作用实例,调用时直接抛出 no active effect found 错误。
- ✅ 正确:创建 AbortController 后立刻注册 onCleanup(() => controller.abort()),再发起 fetch
- ❌ 错误:先 await 某个初始化操作,再调 onCleanup —— 此时响应式追踪早已结束
取消 API 请求的完整写法
这是最典型也最关键的使用场景。用户快速输入搜索词时,旧请求必须中断,避免响应返回后错误地覆盖新状态。
- 每次 watchEffect 触发都新建 AbortController 实例
- 把 controller.signal 传给 fetch 或 axios(1.5+ 支持 signal)
- 在 onCleanup 中调用 controller.abort()
- 在 .then 或 .catch 中检查 signal.aborted 或捕获 AbortError,只处理真实错误
加 cancelled 标记做双重保险
即使用了 AbortController,仍存在极小概率:abort 刚触发,fetch 已 resolve 但还没走到 .then。这时需额外标记防止状态污染。
- 定义 const cancelled = ref(false)
- 在 onCleanup 中设 cancelled.value = true
- 在请求成功回调里加判断:if (!cancelled.value) result.value = data
- 错误处理中跳过 err.name === 'AbortError'


















