第 3 卷
}))
}
这里我们看到 Promise.all(...),这代表并发执行所有 disposer。如果我们深入 clear() 方法就会发现,并发执行前还有一个逆序的逻辑。
// utils.ts 里 DisposableList.clear() 的完整实现
clear() {
const values = [...this.map.values()] // 取出所有,按注册顺序
this.map.clear() // 清空
return values.reverse() // 反转成「后注册的先返
}
第三环:单个 disposer 逆序执行自己的清理函数。
// fiber.ts 里 effect() 内部的 dispose()(节选)
for (const disposable of disposables.splice(0).reverse()) { /
// ↑ splice(0) 清空数组并返回原顺序,reverse()
当我们深入单个 disposer 内部,又看到另一个 reverse(),这里我们要搞清楚,这里的 reverse() 是针对单个 disposer 内的不同步骤。把这两个 reverse() 的逻辑结合起来看,就能得出一个结论:多个 disposer 按注册顺序逆序启动,如果这些 disposer 本身全部都是同步函数,它们会按逆序依次执行,但如果某些 disposer 内部有异步逻辑,那么它们虽然会逆序启动,但并发完成的顺序不能确定。
所以如果你的一组拆除步骤有先后依赖,比如必须先停止轮询,才能关闭连接,正确做法是把它们写进同一个 disposer 里,作为一条清理链依次 await,靠 disposer 内部的“排队”来保证顺序。
fiber.dispose() ← 触发卸载
│
▼
_unload() ← 插件卸载的真正执行者
│
▼
_disposables.clear() ← 其内部 values.reverse():逆序
│
▼
Promise.all 并发启动 wrapper ← 每个 wrapper 触发它那个 disposer
│
▼
disposables.splice(0).reverse() ← 单个 disposer 内部,逆序执
本讲小结
今天这一讲,我们完成了迈向 Cordis 世界的第一步,也是从“传统的手动资源管理方式”到 “动态可组合应用”的重要起点。
我们通过 heartbeat 插件体会到了可撤销副作用的魅力:把 setInterval 和 clearInterval 这对“前进与后退”,写进同一个 ctx.effect,框架便会在插件卸载时替你执行清理函数。沿着这个例子深入源码,我们看到了框架如何在卸载时组织并逆序执行这些清理逻辑。
这背后真正的变化是:你不再手动维护零散的清理代码,而是把“如何建立”与“如何撤销”写在一起,交给框架在卸载时兑现;框架负责调用你提供的清理函数,并按照逆序执行,让环境尽可能回到副作用发生之前的状态。
这,就是“时之可逆”的本质——不是真的逆转时间,而是让每一次副作用都携带一条可靠的 “倒带”路径,使环境能够被干净地回收。
这节课我们解决了“时间”维度的问题,单个组件能否安全地来、安全地走。但前面还有一个更现实的问题等着我们:当多个组件同时存在时,它们之间的依赖关系怎么处理?一个服务下线
注:本讲 GitHub 链接
思考题
- 你来写一个插件,ctx.effect 里只做“前进”(比如 setInterval),不 return 清理
函数,然后挂载它、再卸载。Cordis 会不会报错,那个定时器最后谁来清理?
- 用一个 effect 依次登记三个资源:先打开文件,再建立连接,最后启动轮询。每个资源都
提供自己的清理函数(关闭文件、断开连接、停止轮询)。那么卸载时,这些清理函数按什么顺序执行?为什么?
欢迎你把运行结果分享出来。如果你觉得这节课对你有帮助,也欢迎分享给其他朋友,我们下节课再见!
© 版权归极客邦科技所有,未经许可不得传播售卖。页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
全部留言 (7)
最新精选

邋遢的流浪剑客
2026-08-26 来自上海
思考题使用dsh写代码验证结果如下:
1)ctx.effect 里启动 setInterval 但不返回 disposer 时,Cordis 不会报错;插件卸载后定时器仍然继续 tick。原因是 Cordis 只管理 effect 显式返回或 yield 出来的清理函数,不会自动追踪 JS runtime 资源。
2)一个 effect 依次登记“关闭文件、断开连接、停止轮询”三个清理函数时,卸载顺序是反向的:先停止轮询,再断开连接,最后关闭文件。Cordis 内部用 disposer 数组收集,卸载时 reverse() 后执行,也就是 LIFO 后进先出
作者回复: 赞👍
