08 CORDIS / RESOURCE OWNERSHIP

清理函数挂在哪一层,会改变等待顺序

同样要释放资源,兄弟项可以重叠,组合项会依次等待。切换登记方式和轨迹阶段,观察谁还在等待。

01 / 持有方式

图中连线表示清理函数的持有关系。yield 不会重写 Scope 的 Fiber.parent;原 disposer 是否移出顶层名单,取决于同 owner 中的函数身份。

兄弟 effect

逆序开始,异步清理仍会重叠

A 先登记、B 后登记。Fiber 反转顶层名单后,用 Promise.all 等待各项;A 可以在 B 仍待完成时结束。

02 / 选择轨迹阶段

01 / B 开始

B 已开始异步清理,A 尚未进入。

B:start
02 / A 开始

B 尚未完成,A 的清理也已开始。

A:start
03 / A 结束

实验先放行 A;B 仍然等待自己的 Promise。

A:end
04 / B 结束

再放行 B,所有顶层清理结束,Owner 的卸载才完成。

B:end

清理函数的持有关系 / 手机显示对应持有路径

查看本组登记代码返回持有关系图

登记形状节选,省略具体清理函数与受控 Promise。完整可运行断言见下载包。

inner.effect(() => releaseA)
inner.effect(() => releaseB)
逆序开始,异步清理仍会重叠A 先登记、B 后登记。Fiber 反转顶层名单后,用 Promise.all 等待各项;A 可以在 B 仍待完成时结束。 顶层持有 顶层持有 Owner Fiber顶层清理名单 等待全部顶层项 等待全部顶层项 等待全部顶层项 已等待卸载完成 effect A先登记 未开始 等待中 已结束 已结束 effect B后登记 等待中 等待中 等待中 已结束

持有清理函数 · 描边加粗:本阶段关注项 · 阶段状态为轨迹示意

  • effect AOwner Fiber → effect A 未开始 等待中 已结束 已结束
  • effect BOwner Fiber → effect B 等待中 等待中 等待中 已结束
完整实验轨迹先后关系,非耗时
  1. B:startB 开始
  2. A:startA 开始
  3. A:endA 结束
  4. B:endB 结束

确切 disposer

Scope 纳入组合,tail 会等待它

原 rawDispose 从当前 Fiber 顶层移入组合。组合按逆序清理 B、Scope、tail;Scope 的异步清理结束前,tail 不会运行。

02 / 选择轨迹阶段

01 / B 结束

B 为本组的同步清理,已经完成;接着才进入 Scope。

B
02 / Scope 开始

Scope 正在等待。tail 由同一组合持有,因此尚未调用。

scope:start
03 / Scope 结束

受控 Promise 放行,Scope 清理已结束;下一项是 tail。

scope:end
04 / tail 结束

最后执行 tail,组合与 Owner 的清理结束。

tail

清理函数的持有关系 / 手机显示对应持有路径

查看本组登记代码返回持有关系图

登记形状节选,省略具体清理函数与受控 Promise。完整可运行断言见下载包。

inner.effect(function* () {
  yield releaseTail
  const scope = createScope(inner, key)
  yield scope.rawDispose
  yield releaseB
})
Scope 纳入组合,tail 会等待它原 rawDispose 从当前 Fiber 顶层移入组合。组合按逆序清理 B、Scope、tail;Scope 的异步清理结束前,tail 不会运行。 顶层持有 Owner Fiber顶层只保留组合 等待全部顶层项 等待全部顶层项 等待全部顶层项 已等待卸载完成 组合 effect内部按逆序等待 清理中 清理中 清理中 已结束 releaseTail最早提交,最后清理 未开始 未开始 未开始 已结束 Scope rawDispose确切函数被收集 未开始 等待中 已结束 已结束 releaseB最后提交,先清理 已结束 已结束 已结束 已结束

持有清理函数 · 描边加粗:本阶段关注项 · 阶段状态为轨迹示意

  • releaseTailOwner Fiber → 组合 → releaseTail 未开始 未开始 未开始 已结束
  • Scope rawDisposeOwner Fiber → 组合 → Scope rawDispose 未开始 等待中 已结束 已结束
  • releaseBOwner Fiber → 组合 → releaseB 已结束 已结束 已结束 已结束
完整实验轨迹先后关系,非耗时
  1. BB 结束
  2. scope:startScope 开始
  3. scope:endScope 结束
  4. tailtail 结束

新包装函数

调用目标相同,Scope 仍是顶层兄弟

组合收集的是新包装函数。原 rawDispose 留在 Fiber 顶层,可能在 B 尚未完成时开始;tail 也可能先于 Scope 完成。

02 / 选择轨迹阶段

01 / B 开始

组合先等待 B,Scope 的顶层清理任务也已被安排。

B:start
02 / Scope 开始

原 rawDispose 仍由 Fiber 持有,Scope 此时与 B 同时待完成。

scope:start
03 / B 结束

放行 B。Scope 仍然等待,组合将进入自己的新包装函数。

B:end
04 / tail 结束

包装函数再调用已经启动的 rawDispose,得到 undefined;本组 tail 因而先运行。

tail
05 / Scope 结束

再放行 Scope。Owner 顶层仍等待它,整个卸载此时才完成。

scope:end

清理函数的持有关系 / 手机显示对应持有路径

查看本组登记代码返回持有关系图

登记形状节选,省略具体清理函数与受控 Promise。完整可运行断言见下载包。

inner.effect(function* () {
  yield releaseTail
  const scope = createScope(inner, key)
  yield () => scope.rawDispose()
  yield releaseB
})
调用目标相同,Scope 仍是顶层兄弟组合收集的是新包装函数。原 rawDispose 留在 Fiber 顶层,可能在 B 尚未完成时开始;tail 也可能先于 Scope 完成。 顶层持有 顶层持有 Owner Fiber两个顶层持有项 等待全部顶层项 等待全部顶层项 等待全部顶层项 等待全部顶层项 已等待卸载完成 Scope rawDispose仍由 Fiber 直接持有 未开始 等待中 等待中 等待中 已结束 组合 effect只收集新包装函数 清理中 清理中 清理中 已结束 已结束 releaseTail组合中的较早清理 未开始 未开始 未开始 已结束 已结束 新包装函数() => scope.rawDispose() 未调用 未调用 未调用 已调用 已调用 releaseB本组异步清理 等待中 等待中 已结束 已结束 已结束

持有清理函数 · 描边加粗:本阶段关注项 · 阶段状态为轨迹示意

  • Scope rawDisposeOwner Fiber → Scope rawDispose 未开始 等待中 等待中 等待中 已结束
  • releaseTailOwner Fiber → 组合 → releaseTail 未开始 未开始 未开始 已结束 已结束
  • 新包装函数Owner Fiber → 组合 → 新包装函数 未调用 未调用 未调用 已调用 已调用
  • releaseBOwner Fiber → 组合 → releaseB 等待中 等待中 已结束 已结束 已结束
完整实验轨迹先后关系,非耗时
  1. B:startB 开始
  2. scope:startScope 开始
  3. B:endB 结束
  4. tailtail 结束
  5. scope:endScope 结束