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,触发无限循环的流程是:
- 组件首次渲染时,模板访问
departments,执行getter发起store.query请求,返回一个Promise。 - 请求完成(Promise resolve)后,数据更新触发组件重新渲染。
- 重新渲染时,模板再次访问
departments,又会执行getter发起新的请求,得到新的Promise。 - 新请求完成后再次触发渲染,如此往复形成无限循环。
而加上@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
相关产品推荐
相关产品推荐

