Vue3 Diff算法

Vue3的Diff算法用于高效地更新DOM。简单Diff算法遍历较短子节点,通过key实现复用;双端Diff算法同时比较两端,减少移动次数;快速Diff算法通过预处理构造最长递增子序列,降低DOM操作成本。
摘要由CSDN通过智能技术生成

当新旧vnode的子节点都是一组节点时,为了以最小的性能开销完成更新操作,需要比较两组子节点。用于比较的算法就是Diff算法。

1 简单Diff算法

在进行新旧两组子节点的更新时,应该遍历其中长度较短的那一组。再对比新旧两组子节点的长度,如果新的一组子节点更长,说明有新子节点需要挂载,否则说明有旧子节点需要卸载

  • 减少DOM操作的性能开销
function patchChildren(n1, n2, container) {
   
	if(typeof n2.children === 'string') {
   
		// 省略
	} else if (Array.isArray(n2.children)) {
   
		const oldChildren = n1.children;
		const newChildren = n2.children;
		
		// 子节点长度
		const oldLen = oldChildren.length;
		const newLen = newChildren .length;
		
		const commonLength = Math.min(oldLen, newLen);
		for(let i = 0; i < commonLength; i++) {
   
			patch(oldChildren[i], newChildren[i], container)
		}
		
		if(newLen > oldLen) {
   
			// 挂载新节点
			for(let i = commonLength; i < newLen; i++) {
   
				patch(null, newChildren[i], container)
			}
		} else if (oldLen > newLen) {
   
			// 卸载旧节点
			for(let i = commonLength; i < oldLen; i++) {
   
				unmount(oldChildren[i], container)
			}
			
		}
	}
}
  • 通过key实现复用

新旧两组子节点中的确存在可复用的节点时(key相同),通过DOM的移动来完成子节点的更新更优

DOM可复用并不意味着不需要更新

核心逻辑是:拿新的一组子节点中的节点去旧的一组子节点中寻找可复用的节点。如果找到了,则记录该节点的位置索引。把这个索引称为最大索引。在整个更新过程中,如果一个节点的索引值小于最大索引,则说明该节点对应的真实DOM元素需要移动

移动节点指的是,移动一个虚拟节点所对应的真实DOM节点,而不是移动虚拟节点本身

新children的顺序就是更新后真实DOM节点应有的位置

function patchChildren(n1, n2, container) {
   
	if(typeof n2.children === 'string') {
   
		// 省略
	} else if (Array.isArray(n2.children)) {
   
		const oldChildren = n1.children;
		const newChildren = n2.children;
		
		// 存储寻找过程中遇到的最大索引值
		let lastIndex = 0;
		
		for(let i = 0; i < newChildren.length; i++) {
   
			const newVNode = newChildren[i];
			// 标识新子节点是否存在于旧子节点中
			let find = false;
			
			for(let j = 0; j < oldChildren.length; j++) {
   
				const oldVNode = oldChildren[j];
				// 找到可复用子节点
				if(newVNode.key === oldVNode.key) {
   
					// 一旦找到则设为true
					find = true;
					patch(oldVNode, newVNode, container);
					if (j < lastIndex) {
   
						const prevVNode = newChildren[i - 1];
						if(prevVNode) {
   
							const anchor = prevVNode.el.nextSibling;
							
							insert(newVNode.el, container, anchor);
						}
						
					} else {
   
						lastIndex = j;
					}
					break;
				}
			}
	
			// 到这里仍为false,说明当前newVNode是新增节点,需要挂碍
			if (!find) {
   
				const prevVNode = newChildren[i - 1];
				
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值