daily-plan
daily-plan copied to clipboard
2020-04-10日计划
关于 Vue 的 nextTick 实现
Vue源码详解之nextTick:MutationObserver只是浮云,microtask才是核心!
这篇文章又过了一遍,有了新的理解,原来浏览器可能会有多个task队列,其中用户对于ui的操作的task队列优先级可能比 postMessage
更高。 Vue在某个版本利用 postMessage
实现 nextTick 就出了问题。
比如用户一直在向下滚动视图并且触发 scroll 事件的话,由于这个事件是优先级更高的,可能导致本来应该触发的 nextTick 回调函数最差的情况下被延后了 1000ms 才执行。
如果用 microTask 队列来实现的话,则没有这个问题,因为 UI render 之前是一定会清空 microTask 队列的。一定是能赶在下一次的 UI render 之前执行完任务(比如 dom 变更)
关于 setTimeout 的一个发现
原来
setTimeout(() => {
document.body.style.background = 'blue'
setTimeout(() => {
document.body.style.background = 'red'
})
})
大概率是会触发两次浏览器的渲染的,我误以为由于他们之间的延迟不到 16ms,会被合并成一次。但是其实它会被作为两个 task,而 task 之间穿插了 UI render。
至于为什么有时候不更新,我就真的不知道了,可能是某种优化策略吧。
Vue 2.6 版本的 computed 实现
之前一直没调试,认知里的 computed 一直是 2.4 版本的,每次读取 computed 都会求值,但是只有值发生变化的时候才会去触发 render。
2.6 版本改动很大, 首先 computed watcher
会和它依赖的响应式的值共用一个 dep
,并且会帮助这个 dep 去收集 渲染 watcher
。
所以 2.6 版本计算属性更新的路径是这样的:
响应式的值更新-> 同时通知 computed watcher
和 渲染 watcher
更新 -> computed watcher
把 dirty
设置为 true -> 视图渲染读取到 computed 的值,由于 dirty
所以 computed watcher
重新求值。
computed watcher
内部有个属性 dirty
开关来决定 computed
的值是需要重新计算还是直接复用之前的值。
以这样的一个例子来说:
computed: {
sum() {
return this.count + 1
}
}
首先明确两个关键字:
「dirty」 从字面意义来讲就是 脏
的意思,这个开关开启了,就意味着这个数据是脏数据,需要重新求值了拿到最新值。
「求值」 的意思的对用户传入的函数进行执行,也就是执行 return this.count + 1
- 在
sum
第一次进行求值的时候会读取响应式属性count
,收集到这个响应式数据作为依赖。并且计算出一个值来保存在自身的value
上,把dirty
设为 false,接下来在模板里再访问sum
就直接返回这个求好的值value
,并不进行重新的求值。 - 而
count
发生变化了以后会通知sum
所对应的watcher
把自身的dirty
属性设置成 true,这也就相当于把重新求值的开关打开来了。这个很好理解,只有count
变化了,sum
才需要重新去求值。 - 那么下次模板中再访问到
this.sum
的时候,才会真正的去重新调用sum
函数求值,并且再次把dirty
设置为 false,等待下次的开启……
关于 <script>
标签是否会阻塞页面渲染的问题,昨天测试了下,把引用了 cdn 上的 vue 的 script 标签放在网页的头部,first paint
事件会等待下载完成后才执行,页面是确实会被阻塞的。
所以还是要放在 body底部。