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

Ember.js中@computed与@tracked的区别及移除@computed引发无限循环的原因

Ember.js中@computed与@tracked的区别及无限循环问题解析

核心差异

  • @computed(计算属性):属于Ember传统响应式体系,核心是结果缓存+依赖追踪。它会缓存getter的计算结果,只有当声明的依赖项发生变化时,才会重新执行getter计算新值,默认会自动追踪getter内部用到的响应式属性,避免无意义的重复计算。
  • @tracked(追踪属性):Octane引入的现代响应式方案,核心是属性变更触发更新。被标记为@tracked的属性变化时,所有用到该属性的模板、getter或函数都会重新执行,但不会自动缓存普通getter的结果——每次访问未加@computed的getter,都会从头执行其内部逻辑。

你的代码无限循环原因分析

先看你的原代码:

@computed
get departments() {
  return this.store.query('department', { per_page: 1 });
}

当移除@computed后,departments变成了普通类getter,触发无限循环的流程是:

  1. 组件首次渲染时,模板访问departments,执行getter发起store.query请求,返回一个Promise。
  2. 请求完成(Promise resolve)后,数据更新触发组件重新渲染。
  3. 重新渲染时,模板再次访问departments,又会执行getter发起新的请求,得到新的Promise。
  4. 新请求完成后再次触发渲染,如此往复形成无限循环。

而加上@computed时,计算属性会缓存第一次执行getter得到的Promise,后续访问直接返回缓存结果,不会重复发起请求,自然不会触发循环。

用@tracked替代的正确姿势

如果要改用Octane的@tracked方案,不能直接替换@computed,需要手动处理请求的缓存逻辑:

@tracked departments;

constructor() {
  super(...arguments);
  this.fetchDepartments();
}

async fetchDepartments() {
  this.departments = await this.store.query('department', { per_page: 1 });
}

也可以在组件的didInsertElement钩子(或Glimmer组件的didRender)中发起请求,确保只执行一次,或在特定依赖变化时重新执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 16:48:25