vlambda博客
学习文章列表

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom



尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

图文编辑:开三金


前天看了尤大的直播:


Vue3核心的Typescript,Proxy响应式,Composition解决代码反复横跳都有很棒的文章剖析了。


我总结一下虚拟Dom部分吧,并对比一下React,vdom的重写也是vue3.0性能如此优秀的重要原因。


感兴趣的同学可以到这两个网站了解一下:

https://juejin.im/post/5e6388366fb9a07cda097c47

https://juejin.im/post/5e9ce011f265da47b8450c11


今天,大圣就来给大家深度剖析一下,关于Vue3的虚拟dom那些事:


先说结论,静态标记,upadte性能提升1.3~2倍,ssr提升2~3倍。


怎么做到的呢?


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom
尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

编译模板的静态标记


我们来看一段很常见的代码:

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


vue2中会解析

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


其中前面两个标签是完全静态的,后续的渲染中不会产生任何变化。


Vue2中依然使用_c新建成vdom,在diff的时候需要对比,有一些额外的性能损耗。


我们看下vue3中的解析结果


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom
尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

最后一个_createVNode第四个参数1。


只有带这个参数的,才会被真正的追踪,静态节点不需要遍历。


这个就是vue3优秀性能的主要来源,再看复杂一点的

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


解析结果如下:

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


_createVNode出第四个参数出现了别的数字,根据后面注释也很容易猜出。


根据text,props等不同的标记,这样再diff的时候,只需要对比text或者props,不用再做无畏的props遍历, 优秀!


借鉴一下劝退大兄弟的注释:

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


如果同时有props和text的绑定呢, 位运算组合即可:

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom
尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


text是1,props是8,组合在一起就是9。


我们可以简单的通过位运算来判定需要做text和props的判断, 按位与即可。


只要不是0就是需要比较

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom
尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


位运算来做类型组合,本身就是一个最佳实践,react大兄弟也是一样的:

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


事件缓存:


绑定的@click会存在缓存里:

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom
尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


传入的事件会自动生成并缓存一个内联函数再cache里,变为一个静态节点。


这样就算我们自己写内联函数,也不会导致多余的重复渲染,真是优秀啊!


静态提升:


代码:

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom
尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

vue3和react fiber的vdom


很多人吐槽越来越像React,其实越来越像的api,代表着前端的两个方向。


Vue1.x


没有vdom,完全的响应式,每个数据变化,都通过响应式通知机制来新建Watcher干活。


就像独立团规模小的时候,每个战士入伍和升职,都主动通知咱老李,管理方便。


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

项目规模变大后,过多的Watcher,会导致性能的瓶颈。


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom
尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


React15x:


而React15时代,没有响应式,数据变了,整个新数据和老的数据做diff,算出差异 就知道怎么去修改dom了。


就像老李指挥室有一个模型,每次人事变更,通过对比所有人前后差异,就知道了变化。


看起来有很多计算量,但是这种immutable的数据结构对大型项目比较友好。


而且Vdom抽象成功后,换成别的平台render成为了可能,无论是打鬼子还是打国军,都用一个vdom模式。


碰到的问题一样,如果dom节点持续变多,每次diff的时间超过了16ms,就可能会造成卡顿(60fps)。


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

Vue2.x:


引入vdom,控制了颗粒度,组件层面走watcher通知, 组件内部走vdom做diff。


这样既不会有太多watcher,也不会让vdom的规模过大,diff超过16ms。


真是优秀啊!


就像独立团大了以后,只有营长排长级别的变动,才会通知老李,内部的自己diff管理了。


Vue 2.X

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom



React 16 Fiber:


React走了另外一条路,既然主要问题是diff导致卡顿。


于是React走了类似cpu调度的逻辑。


把vdom这棵树,微观变成了链表,利用浏览器的空闲时间来做diff。


如果超过了16ms,有动画或者用户交互的任务,就把主进程控制权还给浏览器,等空闲了继续。


特别像等待女神的备胎……


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

diff的逻辑,变成了单向的链表,任何时候主线程女神有空了,我们在继续蹭上去接盘做diff。


大家研究下requestIdleCallback就知道,从浏览器角度看,是这样的:

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

大概代码就是这样:

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

神神秘秘的Vue3


这里的静态提升和事件缓存刚才说过了,就不说了。


其实我也很纳闷,这些静态标记和事件缓存,React本身也可以做,为啥就不实现了?


连shouldComponentUpdate都得自己定义,为啥不把默认的组件都变成pure或者memo呢?


唉,也许这就是人生把~


React给你自由,Vue让你持久,可能也是现在国内Vue和React都如此受欢迎的原因吧。

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom

Vue3通过Proxy响应式+组件内部vdom+静态标记,把任务颗粒度控制的足够细致,所以也不太需要time-slice了。


人生啊,小孩才天天研究利弊, 成年人选择我都要,也期待React17的新特性。


关于直播的小花絮:

最后提问期间,强如尤大,也没法回避发量的问题……


可惜没推荐啥护发素,我仔细看了一下,好像vue3发布后,尤大发际线确实提升了~


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


祝大家技术提升的同时也能有乌黑的秀发【耶】


尤大直播后24小时,让大圣带你重写Vue3的虚拟dom


☟扫码关注我,每天8:30看硬核干货☟

尤大直播后24小时,让大圣带你重写Vue3的虚拟dom




“在看”我吗?