You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何未在Effect中调用Signal却触发了无限循环?

Angular Signal 无限循环问题分析

代码实现

export class Service {
  private http = inject(HttpClient)
  private injector = inject(Injector); // Hier wird der Injector geholt

  objectId = signal<string | null>(null);

  private _object = signal<IObject | null>(null);
  object = computed(() => this._object()); // Read-Only access

  // Fehler-Signal, falls die API fehlschlägt
  error = signal<string | null>(null);

  constructor() {
    effect(() => {
      const objectId = this.objectId()
      // this._object.set(null)
      this.error.set(null)

      if (objectId) {
        const secondId = 'secondId'
        console.log('id', objectId)
        this.getObjectById(objectId, secondId)
        return;
      }
    }, { allowSignalWrites: true })
  }

  setObjectId(id: string | null) {
    this.objectId.set(id);
  }

  private getObjectById(objectId: string, secondId: string) {
    this.http.get<IObject>(this.objectUrl + `GetObjectById/${objectId}/${secondId}`).subscribe({
      next: (object) => {
        this._object.set(object)
      },
      error: () => {
        console.log('error')
      },
    })
    console.log(this.object())
    // untracked(() => console.log(this.object()))
  }
}

问题现象

当在getObjectById方法的subscribe前后调用console.log(this.object())时,会触发无限循环;但将日志放在subscribe回调内,或用untracked包裹日志语句则不会。注释掉this._object.set(null)后问题仍存在。

原因解析

核心:Effect的依赖追踪逻辑

  • Effect会自动追踪其执行过程中所有被读取的信号,并将这些信号加入自身的依赖列表,当依赖信号更新时,Effect会重新执行。
  • 你在effect内部调用了getObjectById,而getObjectById里的console.log(this.object())会读取object这个computed信号——此时这个读取操作处于Effect的执行上下文内,所以object会被加入到当前Effect的依赖列表中。
  • 当API请求完成,subscribe的next回调执行this._object.set(object)时,_object信号更新,依赖它的object computed信号也会随之更新。因为object已经在Effect的依赖列表里,Effect会被触发重新执行。
  • Effect重新执行后,又会调用getObjectById,再次读取object,再次触发Effect的依赖更新,最终形成无限循环。

两种解决方式的原理

  • 将日志放在subscribe回调内:subscribe的回调是异步执行的,此时已经脱离了Effect的执行上下文,读取object不会被记录到Effect的依赖列表中,所以_object更新时不会触发Effect重新执行。
  • 用untracked包裹日志:untracked的作用就是屏蔽当前的信号追踪上下文,内部的信号读取不会被加入到Effect的依赖列表,因此不会触发循环。

内容的提问来源于stack exchange,提问作者Lenard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 19:46:20