关于vue计算属性computed的问题

image.png

上面的代码,当我在页面上点击“测试”按钮时,只会触发一次computed中的num函数,同时它不会向watch中的num发送通知。
结果如下:
image.png

但是当我把b--改成b+=2,也只触发一次computed中的num函数,但是能向watch中的num发送通知。
image.png
结果如下:
image.png

按我的理解,计算属性中的内部的变量[a,b]发生变化后,会触发变量本身的Watcher,同时向computed中num的Watcher发送通知,此时应该使其进行两次getter函数,从而打印出两个“get!”,同时watch中的num也应由于computed中的num变化被触发两次。
但结果是vue很巧妙的避开了这些缺陷。
唯一能让我解释得通的说法就是:vue将数据变化的通知放入了微任务,在微任务执行完成后,下一轮的宏任务开始时,比较两个值的变化,此时必且仅会触发一次getter函数,同时再在此后比较前后两个值的变化,如果发生变化,则通知用户定义的watcher[num],否则跳过。
以上是我个人的理解,所以我想求证我的理解是否正确。如果正确,请大神们具体说下vue是如何将更新通知放入微任务的。如果不正确,麻烦各位讲一讲正确的流程。
万分感谢!

阅读 7.1k
2 个回答

Vue 的数据更新确实是异步的。
所以你的例子里面,并不是 this.a 变化后立即更新计算函数 ==> num 变化触发对应的 watch 函数 ==> this.b 变化立即触发计算函数 ==> num 变化触发对应的 watch 函数。

下面是 Vue 文档中相关的部分,异步更新队列

只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部对异步队列尝试使用原生的Promise.thenMutationObserversetImmediate,如果执行环境不支持,则会采用setTimeout(fn, 0)代替。
例如,当你设置vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。
  1. 因为 (1) 里的数字没变
  2. 宏任务与微任务是 JS 引擎为方便处理 Promise 采取的策略,并不开放给开发者,所以不存在“Vue 把XX放进微任务”的说法
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏