关于diff:diff

vue3 Diff算法

patch函数的外围就是Diff算法。

function patch (oldVnode, vnode, parentElm) {
    if (!oldVnode) {
        addVnodes(parentElm, null, vnode, 0, vnode.length - 1);
    } else if (!vnode) {
        removeVnodes(parentElm, oldVnode, 0, oldVnode.length - 1);
    } else {
        if (sameVnode(oldVNode, vnode)) {
            patchVnode(oldVNode, vnode);
        } else {
            removeVnodes(parentElm, oldVnode, 0, oldVnode.length - 1);
            addVnodes(parentElm, null, vnode, 0, vnode.length - 1);
        }
    }
}

patch函数的性能次要是新旧VNode节点,将差别更新到视图上,所以传入参数有新旧2个VNode以及父节点element,先捋清函数的主逻辑:

首先当旧节点oldVnode不存在时,相当于新节点vnode代替没有的节点,所以间接用addVnodes将这些节点批量增加到parentElm下面。

if (!oldVnode) {
    addVnodes(parentElm, null, vnode, 0, vnode.length - 1);
}

同理,当新VNode节点vnode不存在时,相当于把旧的节点删除,所以间接应用removeVnodes函数进行批量的节点删除。

else if (!vnode) {
  removeVnodes(parentElm, oldVnode, 0, oldVnode.length - 1);
}

最初一种状况,就是当旧节点oldVnode和新节点vnode同时存在的状况下,须要判断它们是否属于sameVnode(雷同的节点)。如果是则执行patchVnode函数进行差别比照更新,否则删除旧节点,减少新节点。

if (sameVnode(oldVNode, vnode)) {
    patchVnode(oldVNode, vnode);
} else {
    removeVnodes(parentElm, oldVnode, 0, oldVnode.length - 1);
    addVnodes(parentElm, null, vnode, 0, vnode.length - 1);
}

sameVnode

function sameVnode () {
    return (
        a.key === b.key &&
        a.tag === b.tag &&
        a.isComment === b.isComment &&
        (!!a.data) === (!!b.data) &&
        sameInputType(a, b)
    )
}

function sameInputType (a, b) {
    if (a.tag !== 'input') return true
    let i
    const typeA = (i = a.data) && (i = i.attrs) && i.type
    const typeB = (i = b.data) && (i = i.attrs) && i.type
    return typeA === typeB
}

sameVnode 其实很简略,只有当 keytagisComment(是否为正文节点)、 data同时定义(或不定义),同时满足当标签类型为 input 的时候 type 雷同(某些浏览器不反对动静批改类型,所以他们被视为不同类型)即可。

patchVnode

参考文章

  • answershuto/VueDemo

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理