Effect 的 fiber 什么时候该脱离父级?
一次请求触发了一个后台同步,请求响应已经返回了,同步却被一起中断,只做了一半。
这种任务该用 Effect.forkDetach,让子 fiber 脱离父级;但默认仍然应该用 Effect.forkChild,脱离归属必须是有意识的决定。 forkChild 创建的子 fiber 属于父,父结束时会被自动中断;forkDetach 创建的子 fiber 挂在全局,不随父结束。
之所以默认不脱离,是因为 Effect 的并发是结构化的:子 fiber 的生命周期被包含在父 fiber 之内,这样才不会留下无主的孤儿任务。下面看哪些情形值得打破这条规则,打破之后又由谁来负责。
为什么默认让子任务跟着父走?
Effect.forkChild 在当前 fiber 之下启动子 fiber。父 fiber 结束(成功、失败或被中断)时,还没结束的子 fiber 会被自动中断;父被中断时,中断也会向下传递。这样用户离开页面、父任务失败这类情形,都不会留下没人管的任务,原理见 Effect 的 fiber 是什么,为什么子任务归父任务管?。
forkDetach 脱离之后谁负责?
有些任务本来就不该跟着当前请求一起死,比如一次触发后要跑完的后台同步。这时用 Effect.forkDetach:子 fiber 挂在全局,不随父结束,它的生命周期需要你自己负责。
脱离意味着你放弃了结构保证。没人 join、也没人中断的话,它出了错就没人看见。
forkScoped 和 forkIn 是怎么回事?
Effect.forkScoped 和 Effect.forkIn 提供的是第三种归属:把子 fiber 挂在某个 Scope 上,Scope 关闭时中断。这样任务既不跟着当前父 fiber,也不是无主,而是跟着一个你能明确指出的资源生命周期。Scope 的用法见 Effect 的资源与 Scope。
怎么选?
- 任务应该随当前流程结束:
forkChild,这是默认。 - 任务要在当前流程之外跑完,生命周期由你自己管:
forkDetach。 - 任务应该跟着某个资源的生命周期:
forkScoped或forkIn。
这几个 fork 的更多细节,比如 fork 返回时子 fiber 还没真正开始执行带来的竞态,见 Effect fork 家族。
本文整理自 Effect 教程中关于 fiber 的章节,没有再亲自运行过相关代码,也没有核对具体的 effect 版本号。forkScoped与forkIn的具体用法在原文里只是点到,细节请以你所用版本的文档为准。