← 返回目录

第 3 卷

第 3 / 5 卷日期:

复制代码 1// service.ts 里 Service 构造函数的关键一行(节选)

2self.ctx.reflect.provide(name, self, this[symbols.check])

它把 this(这个服务实例)注册进上下文——你平时写的 ctx.provide(...) 本质上就是转发给 reflect.provide(...) 的。而且,reflect.provide 在注册之后、以及撤

销(返回的清理函数)时,都会调用 notify() 去通知所有依赖方。

前三步是“停”和“起”共用,我们先看这三步:

  • notify 找到受影响的插件:

复制代码

1// reflect.ts里notify()的核心(节选,去掉了filter过滤与返回值收集)
2notify(names) {
3for(construntimeofthis.ctx.registry.values()) {
4for(constfiberofruntime.fibers) {
5lethasUpdate =false
6for(constnameofnames) {
7if(!(nameinfiber.inject))continue //没声明这个依赖→跳过
8hasUpdate =true
9fiber._checkImpl(name) //重新检查:服务还在吗?
10}
11if(!hasUpdate)continue //一个依赖都没变→这个fiber不用动
12fiber._refresh() //重新计算依赖指纹
13}
14}
15}

它遍历所有插件,只挑出「inject 里声明了 greeter 的那些 fiber:对每个声明了 greeter 的 fiber 做 _checkImpl,最后只要确实有依赖变化被查到,就做一次 _refresh。

复制代码 1// fiber.ts 里 _checkImpl 的核心(节选)

2_checkImpl(name) {

3constimpl =this.ctx.reflect._getImpl(name,true)//去store重新查:greeter还
4if(!impl)returndeletethis._store[name]//查不到了→把fiber自己记的
5this._store[name] = impl//还查得到→更新记录
6}

每个 fiber 都维护着一份 _store,记着“我依赖的那些服务的当前实例”。_checkImpl 做的就是把这份记录刷新一遍:服务没了就删掉,还在就更新成最新实例。

  • _refresh 重算“依赖指纹”(node_modules/@deepseek-

ai/cordis/src/fiber.ts):

复制代码 1// fiber.ts 里 _refresh 的核心(节选)

2_refresh() { 3let epoch = ''

4for(constnameofObject.keys(this.inject)) {
5constimpl =this._store[name]
6if(!impl) { epoch =INACTIVE;break} //有依赖缺失了→标记为「不活跃」
7epoch +=':'+ impl.fiber.uid //依赖齐全→拼出它们的uid指纹
8}
9this._setEpoch(epoch)
10}

它把“当前依赖的那些服务的 uid”拼成一个字符串指纹(epoch)。依赖齐全,指纹是一串 uid;缺了哪个,指纹直接变成 INACTIVE。

  • 是分叉点——_setEpoch 拿新指纹和旧指纹一比,决定走哪条路

(node_modules/@deepseek-ai/cordis/src/fiber.ts):

3const oldEpoch = this._runner.epoch

4if(epoch === oldEpoch)return//指纹没变→什么都不做(论文说的「无关
5this._runner.epoch= epoch
6if(epoch !==INACTIVE&& oldEpoch ===INACTIVE) {
7this._reload()//指纹从「无」变「有」→插件起
8}else{
9this._unload()//指纹从「有」变「无」→插件停
10}
11}

这就是“响应式”最核心的决策点:用依赖指纹有没有变、往哪个方向变,决定插件是停、是起、还是不动。它正好对应论文里说的三种情况——激活(activating,从无到有)、停用

(deactivating,从有到无)、无关(neutral,没变)。

下面我们来看两个分支各自的实现:

分支 A:_unload —— 插件停。_unload() 内部就是第一讲见过的那句 Promise.all(this._disposables.clear()...),把 fiber 上注册的所有 effect 一次

性清空。所以“停”的实现,就是复用第一讲的注册即副作用 + 倒序回收,consumer 当初注册的所有东⻄,在这一刻被逆序清掉。

分支 B:_reload —— 插件起。

复制代码 1// fiber.ts 里 _reload 的核心(节选)

2private async _reload() {

3this.store= { ...this._store}//①用最新检查到的依赖,重建store
4...
5this.config=this._resolveConfig(this._config)//②重新解析配置
6awaitthis._execute(this._runner)//③★重新执行插件的apply!
7}
全站分卷索引 · 5 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷