【通俗易懂】虚拟 DOM,如何更高效 DIFF
我们都知道,通过虚拟 DOM,可以减少 DOM 操作,提高页面渲染性能
要实现虚拟 DOM,主要三部曲:
compile view to vnode
diff vnode 的变化
patch vnode 变化到实际的 DOM
假想的黑粉:"所以这篇文章是要深入虚拟 DOM 的实现原理和实现细节吗?"
非也非也,我们开始愉快地进入正题吧
三部曲中,diff 的性能很关键,所以一般对 vnode 的 type 和 key 作比较,如果不一致,则该 vnode 及以下孩子们全部干掉(好残忍,无法直视(>﹏<)),用新的直接替换,不再往下对比。
假想的黑粉:“这个大家都懂,所以文章至此可以结束了?”
还没。。。还没开始(# ̄▽ ̄#)
要 diff,那就得有 diff 的两个 vnode,一个 old vnode,一个 new vnode,那 new vnode 如何产生的呢?
假想的黑粉:“简单啊,把 old vnode 赋值给 new vnode”
额~,像以下这样吗?
可以看到新旧一致,无论如何赋值都是同个对象,无从对比啦
假想的黑粉:“我是想说 clone 一个啦,shadow 就行了” <( ̄︶ ̄)>
额~,像以下这样吗?
可以看到更改了 new vnode 的 a1 值,old vnode 的 a1 值也被改了,也就无法得知变化了
假想的黑粉:“刚为了性能考虑说了 shadow copy,那实在不行就 deep copy 吧”
额~,像以下这样吗?
看上去没什么问题,功能是可以实现了,但这篇文章是要讲 更 高效 diff,上面方案有两个较不好的性能问题:
deep copy 造成资源浪费,没更新的结点也被复制了一份
每次要遍历所有 vnode 进行对比,无论该 vnode 有没产生变化
假想的黑粉:“看样子你是有更好的方案,有什么花招赶紧使出来吧~”
那就让我慢慢道来,先来个中横线分割一下先( ̄︶ ̄)↗
只要避免上面提到的两点对性能的影响,即可更高效 DIFF,对应的措施如下:
按需 copy:没出现变化的 vnode 不作 copy
按需 diff:没出现变化的 vnode 不作 diff
假设 vnode 的数据结构以及图形表示如下:
当把 a1_1 的值更改为 2 时, 我们希望只对以下高亮节点进行 shadow copy 或赋值,以下即为 new vnode
所以在对比 old vnode 和 new vnode 时,只有下图高亮的节点需要进行比对
当 a2 和 b 节点下面的子节点越多时,copy 和 diff 所带来的性能收益就越明显
最后献上这种方案的极简单极粗糙的实现(update 方法,只考虑对象,没考虑数组)以更好的从代码层面去理解这种思路
版权声明: 本文为 InfoQ 作者【Daniel】的原创文章。
原文链接:【http://xie.infoq.cn/article/39c14ead37c680a4226882959】。文章转载请联系作者。
评论