Promise修改Vue响应式数据:位置为何影响onUpdated触发次数?
问题分析:两种写法触发
onUpdated次数不同的原因 先看两种写法的代码:
第一种写法
const list = reactive([1, 2, 3, 4, 5]); const handleClick = () =>{ list.push(...[11, 12, 13, 14, 15]); list.push(...[16, 17, 18, 19, 20]); Promise.resolve().then(() => { list.push(33) }); };
第二种写法
const list = reactive([1, 2, 3, 4, 5]); const handleClick = ()=>{ Promise.resolve().then(() => { list.push(33) }); list.push(...[11, 12, 13, 14, 15]); list.push(...[16, 17, 18, 19, 20]); };
核心原因:Vue异步批量更新机制 + 微任务执行顺序
Vue的响应式更新是异步批量处理的:同步修改响应式数据时,Vue不会立刻更新DOM,而是把所有更新操作放到队列里,等当前同步代码执行完后,通过微任务一次性批量处理队列更新,触发一次onUpdated钩子。
第一种写法的执行流程
- 同步代码先执行两次
list.push,这两次修改被Vue加入同一个更新队列,同时Vue调度一个更新微任务。 - 接着注册Promise的
then回调,这个回调作为另一个微任务,排在更新微任务之后。 - 同步代码执行完后,事件循环处理微任务:
- 先执行Vue的更新微任务:批量处理两次push的更新,DOM更新完成,触发第一次
onUpdated,此时更新队列清空。 - 再执行Promise的
then回调:修改list.push(33),Vue发现没有待处理的更新任务,重新调度一个新的更新微任务。 - 新的更新微任务执行时,处理
push(33)的更新,DOM再次更新,触发第二次onUpdated。
- 先执行Vue的更新微任务:批量处理两次push的更新,DOM更新完成,触发第一次
第二种写法的执行流程
- 同步代码先注册Promise的
then回调,这个回调作为微任务A加入队列。 - 接着执行两次
list.push,这两次修改被Vue加入更新队列,同时Vue调度一个更新微任务B,排在微任务A之后。 - 同步代码执行完后,事件循环处理微任务:
- 先执行微任务A:修改
list.push(33),此时Vue发现已有待处理的更新微任务B,就把这次push(33)的更新直接加入现有更新队列,不新增微任务。 - 再执行微任务B:Vue批量处理所有三次更新(两次push + push(33)),一次性完成DOM更新,只触发一次
onUpdated。
- 先执行微任务A:修改
简单说,第二种写法里Promise回调的修改赶上了同步代码触发的更新队列,被合并成一次更新;第一种写法里Promise回调的修改是在第一次更新完成后才触发的,只能单独触发一次新的更新。
内容的提问来源于stack exchange,提问作者KimSohyun
相关产品推荐
相关产品推荐

