先记住这个答案
computed 描述一个由响应式输入得到的纯派生值,并按依赖缓存结果;watch 描述某些来源变化后执行什么副作用,可以处理请求、外部控件或保存流程。用 watch 把可计算结果再写进另一份 state,会增加两份数据保持一致的负担。反过来,把请求或状态修改塞进 computed getter,又会让读取结果触发操作。选择依据是逻辑目的,而不只是它是否依赖某个变量。
- 纯派生值用 computed 表达输入到结果的关系
- 外部同步用 watch 明确来源、执行和清理
- 一次用户命令也可以直接放事件,不必先转成状态观察
价格合计不需要再保存一份可过期状态
购物列表、数量和优惠规则已经决定总价时,可以由 computed 计算合计。若另外保存 total,再通过多个 watch 随列表和规则变化更新,就必须保证每种变更都触发正确更新,删除商品或切换规则时很容易漏掉某条同步路径。
computed 也应保持纯粹,不能计算总价时顺便修改商品数组或发起结算请求。读取可能复用缓存,执行时机与用户命令不是一一对应。需要昂贵计算时可以评估依赖与算法成本,但缓存不会修复错误的数据来源和副作用设计。
自动保存需要处理外部任务生命周期
草稿改变后延迟保存属于与远端状态同步的流程,可以用 watch 观察真正需要保存的内容。回调还应处理取消、防抖、保存版本、错误与迟到结果,避免旧请求覆盖新内容。这个过程的结果不只是一个从输入直接算出的值,因此不适合藏在 computed getter 中。
如果用户明确点击保存按钮,则事件处理器本身已经知道这次命令和提交参数,不必先设置一个 shouldSave 布尔值,再由 watch 猜测是否应该发送。自动保存与手动保存可以共存,但要统一版本和成功状态,不能让两条路径相互覆盖。
派生结果也可以作为外部同步的输入
例如先用 computed 从数据得到图表配置,再由 watch 在配置变化时更新第三方图表实例。两者组合时职责仍然清楚:computed 负责纯粹计算,watch 负责命令式同步与资源管理。若配置每次返回新对象,还需判断引用变化是否代表真正的业务变化。
watchEffect 可以自动收集同步执行期间的读取,但也不是 computed 的替代缓存,更不应被当成任意代码的默认落点。验收时可以先移除外部同步,验证纯计算对不同输入的结果;再验证同步的参数切换、清理与异常流程,避免把展示正确当作异步流程也正确的证据。
容易答错的地方
- watch 能算出相同结果,所以完全等价于 computed
- 最终某次显示一样不代表数据模型相同。watch 写入额外 state 引入更新时序与一致性维护,computed 直接表达派生关系;选择应看是否需要独立存储和副作用。
- computed 缓存结果,所以适合缓存请求 Promise
- 异步请求涉及启动、失效、取消与错误等协议,不能只因为返回 Promise 也算一个值就把它塞进 getter。应采用明确的数据加载与缓存方案,再让 computed 派生展示状态。
面试官还会怎么问?
用户可以手工改总价,还能只用 computed 吗?
手工报价可能是独立草稿,不能再假定完全由商品规则决定。可以区分建议价与确认报价,明确覆盖和重置时机,而不是用自动派生覆盖用户修改。
可写 computed 能代替所有 watch 吗?
不能,它适合明确的读写转换,不提供通用外部任务生命周期。复杂异步同步、清理和重试仍需要单独建模。
watch 回调更新它监听的来源会怎样?
可能形成重复触发甚至循环,也可能是有明确终止条件的业务修正。应检查数据流和条件,避免两个监听器互相写入维持本可直接计算的关系。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。