vue 和 uniapp 的 diff 算法有何区别

vue 的 diff 算法网络上介绍他的文章有很多,介绍的也很详细,总结一句话就是同层级比较,不会跨层级比较。uniapp 的 diff 算法在社区里面几乎不曾有人介绍过,这里我详细的介绍一下。

uniapp 的 diff 算法

在 uniapp 中他把 diff 算法放在了运行时的 patch 函数里面,每次调用数据更新的时候,uniapp 都会调用他的 patch 方法。方法如下

var patch = function(oldVnode, vnode) {
  var this$1 = this;
  if (this.mpType === 'page' || this.mpType === 'component') {
    var mpInstance = this.$scope;
    var data = Object.create(null);
    // ...我把与本篇章无关的内容给去除掉了
    // 这里的 diff(data, mpData) 就是调用了他的 diff 算法
    var diffData = this.$shouldDiffData === false ? data : diff(data, mpData);
    // ... 还有很多操作
  }
};
function _diff(current, pre, path, result) {
    if (current === pre) { return }
    var rootCurrentType = type(current);
    var rootPreType = type(pre);
    if (rootCurrentType == OBJECTTYPE) {
        if (rootPreType != OBJECTTYPE || Object.keys(current).length < Object.keys(pre).length) {
            setResult(result, path, current);
        } else {
            var loop = function ( key ) {
                var currentValue = current[key];
                var preValue = pre[key];
                var currentType = type(currentValue);
                var preType = type(preValue);
                if (currentType != ARRAYTYPE && currentType != OBJECTTYPE) {
                    if (currentValue !== pre[key] && nullOrUndefined(currentType, preType)) {
                        setResult(result, (path == '' ? '' : path + ".") + key, currentValue);
                    }
                } else if (currentType == ARRAYTYPE) {
                    if (preType != ARRAYTYPE) {
                        setResult(result, (path == '' ? '' : path + ".") + key, currentValue);
                    } else {
                        if (currentValue.length < preValue.length) {
                            setResult(result, (path == '' ? '' : path + ".") + key, currentValue);
                        } else {
                            currentValue.forEach(function (item, index) {
                                _diff(item, preValue[index], (path == '' ? '' : path + ".") + key + '[' + index + ']', result);
                            });
                        }
                    }
                } else if (currentType == OBJECTTYPE) {
                    if (preType != OBJECTTYPE || Object.keys(currentValue).length < Object.keys(preValue).length) {
                        setResult(result, (path == '' ? '' : path + ".") + key, currentValue);
                    } else {
                        for (var subKey in currentValue) {
                            _diff(currentValue[subKey], preValue[subKey], (path == '' ? '' : path + ".") + key + '.' + subKey, result);
                        }
                    }
                }
            };

            for (var key in current) loop( key );
        }
    } else if (rootCurrentType == ARRAYTYPE) {
        if (rootPreType != ARRAYTYPE) {
            setResult(result, path, current);
        } else {
            if (current.length < pre.length) {
                setResult(result, path, current);
            } else {
                current.forEach(function (item, index) {
                    _diff(item, pre[index], path + '[' + index + ']', result);
                });
            }
        }
    } else {
        setResult(result, path, current);
    }
}

可以看出在 patch 方法里面他会进行调用 diff 方法,这个diff方法其实最后就是调用了 _diff 方法。根据上面 _diff 的逻辑可以得出以下几点。

  1. 改变后的值不为对象和数组时,会判断改变前和改变后的值是否相同,不相同并且他们都不是null和 undefined那么就会调用 setResult 的方法来修改值。
  2. 修改后的值为对象的话,会判断看下修改前的值是不是对象,不是对象或者Object.keys的长度修改后的值比修改前的值要小,那么就会直接调用 setResult的方法。
  • 如果修改前的值是对象并且 Object.keys的长度修改后的值比修改前的值要大,他会重新调用_diff方法,如果值相同直接跳出这一次循环,进入下一次循环,key里面的值不为数组和对象的话那么直接调用 setResult 的方法,其实就是第一点
  1. 修改后的值为数组的话
  • 如果修改前的值不为数组,那么就直接调用 setResult 方法
  • 如果修改前的值为数组,那么他会遍历修改后的数组,把里面的每一项进行diff,接下来的步骤跟第一,第二步一样
  1. 如果修改后的值为null或者undefined的话,那么就直接调用 setResult 方法
    setResult 其实就是改变对象的key和value值 方法如下:
	function setResult(result, k, v) {
    // if (type(v) != FUNCTIONTYPE) {
        result[k] = v;
    // }
}

对 vue 和 uniapp 的 diff 算法有个大致了解以后,我们来对比下他们的不同点。

相同点

如果非要说相同点的话,那么就只有一个,他们都调用了一个叫 patch 的方法,这个方法里面有他们各个的 diff 算法。

不同点

  1. vue的diff算法是针对于vnode的,uniapp的diff算法是针对于数据的。
  2. vue的diff算法是同层级优先,不会跨层级比较,也就是说父亲不会和他的孩子进行比较,uniapp的是只跟他相同字段的值进行比较。
  3. vue的diff算法他会把能复用的节点进行复用,如果新的节点个数比老的节点个数多的话,并且是一个全新的节点的话,那么他会直接创建一个节点。uniapp是分了上面那4个场景进行比较,而且全都是对数据进行比较。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值