导读
我们在读源码的时候,往往有非常多的疑问,例如,这里的代码为什么要这么写?
当我们遇到问题时,假如我们不太确定自己的猜测是否正确,我们要怎么验证自己的猜想呢?
下面我用一个例子来说明
我的猜想是什么
watch 的 options flush 参数(文档链接),分别对应了 effect 不同的执行时机(组件更新前、中、后)
但是从在看源码中,前中后分为了 3 个执行队列,且这三个执行队列是先后同步执行的,中间没有异步,都在这部分的代码同一个执行栈中
因此我猜:flush: post 时,watch callback 执行是在组件更新后,且在渲染前
下面是我在阅读的 vue scheduler 源码,看不懂也没关系,大概看一下就行,只要能看出中间没有异步即可
function flushJobs() { // .... // 执行组件数据更新前的队列 flushPreFlushCbs(seen) // .... try { // 执行组件数据更新队列 for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { const job = queue[flushIndex] if (job && job.active !== false) { callWithErrorHandling(job, null, ErrorCodes.SCHEDULER) } } } finally { // .... // 组件数据更新后的队列 flushPostFlushCbs(seen) // .... } }
这里有 3 个队列,分别对应组件数据更新前、中、后。
为了验证我的猜想,最简单的办法是,自己写一个简单的 demo 并进行调试。如果不懂如何调试 vue3,可以参考这篇文章
编写验证的 demo
先说一下思路,既然要确定,flush: post
时 ,watch callback 是不是在组件更新后、渲染前执行,我们只需要在 watch 的 callback 中停止代码,然后查看界面是有变化
如果停止时,界面并没有更新,则证明 watch callback 是在渲染前执行
如何在 callback 中停止代码?使用 debugger?
这是个非常容易出错的点,而且非常隐藏。debugger 能够触发 chrome 的断点调试,让 js 代码停止执行,但是它并没有停止渲染!
由于渲染没有停止,debugger 导致界面更新,会得出完全相反的结果!
因此,验证方法的正确性,也很重要!否则可能会得出完全相反的结果!
要让 js 和 render 都停止,我们可以使用 alert
于是我们可以写以下的验证代码,在 watch 的 callback 中,加一行 alert。
<!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <meta name='viewport' content='width=device-width, initial-scale=1.0'> <meta http-equiv='X-UA-Compatible' content='ie=edge'> <title>Document</title> <script src='../vue/dist/vue.global.js'></script> </head> <body> <div id='app'> </div> <script> const App = { template: ` <p>{{ name }}</p> `, setup() { const name = Vue.ref('vue setup') Vue.watch(name, () => { console.log('watch post', name.value) alert() debugger }, { flush: 'post' }) setTimeout(() => { name.value = 'vue mounted change' }, 3000) return { name } } } let vm = Vue.createApp(App).mount('#app') </script> </body> </html>
运行结果
跟我的猜想符合, flush:post
时,watch callback 是在组件数据更新,UI 渲染之前的执行的
总结
读源码时,往往不是非常顺利的,也需要点耐心。遇到问题,需要一些方法论,去尝试理解、解决问题。
先提出猜想,再做 demo 验证,加深理解。
有时候猜想也不一定是对的,也有可能是,猜想是对的,但是验证方法不对(就好像如果是用了 debugger 去停止代码),导致了得出了相反的结论。这时候我们需要点耐心,反复的思考。
如此重复,到最后,我们会对源码有更深的理解。