wevu 中的 setData 什么时候触发?
很多同学会把“响应式值变了”直接等同于“立刻调用 setData”。 在 wevu 里,这两件事是分开的:状态变化先进入调度,再按策略决定是否、何时、以及用多大 payload 调 setData。
这也是 wevu 在小程序里能保持较好性能的关键。
一句话结论
setData 触发的前提不是“有赋值”,而是:
- 运行时仍处于已挂载状态;
- 本轮调度最终产出了非空更新 payload;
- 适配器存在可用的
setData方法。
换句话说,赋值只是“候选更新”,不是“必然下发”。
触发时机分三类
1. 首次挂载时会触发一次初始化更新
runtime 挂载后,wevu 会主动执行一次 job(),把首帧状态推到视图层。 这一步是为了确保初始 data/setup/computed 的可视数据完整进入模板。
2. 响应式依赖变化后,在微任务批量触发
当你修改了被跟踪的状态(含 state、props/attrs、setup 返回的 ref/reactive 等),会先触发 effect 的 scheduler。 scheduler 不会立即 setData,而是通过队列合并到同一轮微任务里统一处理。
这意味着同一个同步调用栈里的多次写入,通常只会换来一次更新 flush。
3. patch 模式下,按变更路径触发增量更新
当策略是 patch 时,wevu 会记录变更路径,优先走增量 payload。 如果命中回退条件(例如路径过多、payload 过大、需要全量快照),才切回 diff 全量快照对比。
这个设计保证了“平时快、异常情况稳”。
哪些情况不会触发 setData
下面这些场景常见但不会下发:
- 值没有真实变化(例如
Object.is结果相等); - 本轮 diff/patch 结果为空(没有可见变化);
- 实例已经卸载(
isMounted() === false); - 字段被
pick/omit等配置过滤后,不在下发范围; - 不可序列化值被规范化后没有产生有效输出。
所以看到“代码执行了但没 setData”不一定是 bug,很多时候是有意的性能保护。
为什么这套机制在小程序里更高效
1. 微任务批处理,减少调用频率
频繁 setData 的代价很高,wevu 默认把同 tick 改动合并后再下发,显著降低桥接次数。
2. 差量 payload,减少传输体积
wevu 不是盲目整包下发,而是优先只发变化路径。 在大对象/大列表场景下,这一点通常比“每次全量推送”更省。
3. 有阈值回退,不把极端场景做成性能陷阱
当 patch 的性价比变差时,自动回退到 diff。 这避免了“为了增量而增量”导致的长尾性能问题。
4. 可配置调试,便于观察真实开销
setData 支持 debug 信息回调与采样,可以看到当前是 patch 还是 diff、为何回退、payload 键数与估算体积。 这让性能调优从“猜”变成“看数据”。
常见误解
误解 1:响应式等于即时 setData
更准确的说法是:响应式变化会“触发调度资格”,真正下发由 flush 阶段决定。
误解 2:增量模式一定比 diff 快
不一定。 wevu 的策略是“优先 patch,但允许及时回退”,目标是总体吞吐稳定,而不是追求单一策略。
误解 3:调用次数少就一定更快
还要看 payload 大小、序列化成本、模板复杂度。 wevu 的优化是“调用频率 + payload 体积 + 回退策略”一起做。
实战建议
- 高频交互优先保证状态结构稳定,减少无意义字段波动。
- 大列表场景关注“实际 payload 键数和体积”,不要只看逻辑层赋值次数。
- 需要时开启
setData.debug,先看回退原因再调参数(如maxPatchKeys、maxPayloadBytes)。
小结
wevu 的核心不是“让 setData 更频繁”,而是“让 setData 更克制、更小、更可控”。 这正是它在小程序场景下保持高性能的主要原因之一。