Virtual DOM 系列三:Diff算法
DOM操作是昂贵的,为了减少DOM操作,才有了Virtual DOM。而Virtual DOM的关键就是通过对比新旧vnode,找出差异部分来更新节点。对比的关键算法就是Diff算法。
历史由来:
diff算法历史悠久,并不是虚拟dom提出来的。早在linux系统中,就有diff命令,用于比较两个文本的差异,还有一个最常用的就是git diff命令,由于比较两个版本之间的差异。Virtual DOM的算法是用来对比新旧虚拟dom的差异。
核心逻辑:
1. creatElement
首先先来分析patch函数的第一种用法:patch(container, vnode).。如何把虚拟dom转化成真正的DOM?
假设每个节点都包含tag,props,children三个属性(按最简单的情况考虑)
step 1: 创建节点;
step 2: 设置属性;
step 3; 遍历子节点,子节点也需要结果step1,2,然后加到当前节点中。
经过分析,我们发现创键DOM,需要用到递归。
代码模拟如下:
function createElement(vnode) {
var tag = vnode.tag;//获取元素的标签
var props = vnode.props || {};//获取元素的属性
var children = vnode.children || [];//获取子节点
if (!tag) {
return null;
}
var ele = document.createElement(tag);//step1:创建元素
// step2:设置属性
var attrName;
for (attrName in props) {
if (props.hasOwnProperty(attrName)) {
ele.setAttribute(attrName, props[attrName])
}
}
//step3:深度遍历子元素,并插入当前节点
children.forEach(element => {
ele.appendChild(createElement(element)); //递归调用
});
return ele;
}
2. updateChild
接着再来分析一下patch函数的第二种用法:patch(oldVnode, newVnode)。如何找出新旧节点的差异,并更新节点?
假设只考虑最简单的情况,只改变以下<li>标签的值。

function updateChild(vnode,newVnode) {
var oldchild = vnode.children || [];
var newchild = newVnode.children || [];
oldchild.forEach(function (childItem, index) {
var newChildItem = newchild[index]; //假设层级相同
if(newChildItem.tag === childItem.tag) {
updateChild(childItem, newChildItem) //如果相同则递归遍历
} else {
replaceNode(childItem, newChildItem)//否则替换dom
}
})
}
function replaceNode(parantNode, oldchildNode, newChildNode) {
var oldelem = oldchildNode.elem; //获取真实dom
var newElem = newChildNode.elem;
//替换dom
parantNode.replaceChild(newElem,oldelem);
}
注:以上代码都是伪代码,只考虑了最简单的情况。
总结:
实际diff算法非常复杂,还需考虑节点的新增,删除;节点的重新排序;节点属性、样式、事件的绑定等。
1. virtual dom是什么?为何使用VD?
虚拟DOM
用JS模拟DOM结构
DOM操作非常昂贵
将DOM对比放在JS层,提高效率
2. 核心API
h('<html 标签名>',{属性},[children])//含有子节点的
h('<html 标签名>',{属性},'text'])//没有子节点,只有文本,如<p>this is VN</p>
patch(container, vnode)//初次渲染
patch(oldVnode, newVnode); //re-render
3. diff算法
creatElement,updateChild逻辑
Virtual DOM 系列三:Diff算法的更多相关文章
- Virtual DOM 系列二:核心API
为了更好的研究Virtual DOM,我选择了snabbdom来学习.相比Vue来说,snabbdom对于研究虚拟DOM更好,因为它里面没有其他干扰的东西,而且源码也比较少,因此研究起来更方便. 1. ...
- Virtual DOM 系列一:认识虚拟DOM
1. 什么是Virtual DOM? Virtual DOM(虚拟DOM)是指用JS模拟DOM结构.本质上来讲VD是一个JS对象,并且至少包含三个属性:tag(html标签),props(标签的属性, ...
- React之虚拟DOM中的Diff算法
一.React中的setState ( 异步函数,异步获取数据 ) 若操作的时间间隔短,它可以将多个setState结合成一个setState,减少虚拟DOM的比对次数,提高性能 二.同层虚拟DOM对 ...
- jvm系列(三):GC算法 垃圾收集器
原文出处:纯洁的微笑 这篇文件将给大家介绍GC都有哪几种算法,以及JVM都有那些垃圾回收器,它们的工作原理. 概述 垃圾收集 Garbage Collection 通常被称为"GC" ...
- 一篇文章教会你如何将DOM转换为virtual DOM
[一.Virtual DOM简介] Virtual DOM是虚拟节点,它通过Javascript的Object对象模拟DOM中的节点,然后通过特定的render方法将其渲染成真实的DOM节点. 浏览器 ...
- diff算法深入一下?
文章转自豆皮范儿-diff算法深入一下 一.前言 有同学问:能否详细说一下 diff 算法. 简单说:diff 算法是一种优化手段,将前后两个模块进行差异化比较,修补(更新)差异的过程叫做 patch ...
- 从 0 到 1 实现 React 系列 —— 3.生命周期和 diff 算法
看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...
- 深入理解react中的虚拟DOM、diff算法
文章结构: React中的虚拟DOM是什么? 虚拟DOM的简单实现(diff算法) 虚拟DOM的内部工作原理 React中的虚拟DOM与Vue中的虚拟DOM比较 React中的虚拟DOM是什么? ...
- react虚拟dom diff算法
react虚拟dom:依据diff算法 前端:更新状态.更新视图:所以前端页面的性能问题主要是由Dom操作引起的,解放Dom操作复杂性 刻不容缓 因为:Dom渲染慢,而JS解析编译相对非常非常非常快! ...
随机推荐
- java的spi 的简单应用
1.什么是java的spi SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制. 目前有不少框架用它来做服务的扩展发现, 简单来说,它就是一 ...
- SLAM+语音机器人DIY系列:(八)高阶拓展——1.miiboo机器人安卓手机APP开发
android要与ROS通讯,一种是基于rosbridge,另一种是基于rosjava库. 相关参考例子工程 rosbridge例子: https://github.com/hibernate2011 ...
- Springboot 系列(十二)使用 Mybatis 集成 pagehelper 分页插件和 mapper 插件
前言 在 Springboot 系列文章第十一篇里(使用 Mybatis(自动生成插件) 访问数据库),实验了 Springboot 结合 Mybatis 以及 Mybatis-generator 生 ...
- [Javascript] js的类和对象
类 graph LR 类-->构造函数 类-->prototype对象 类-->instanceof运算符 类-->constructor属性 类-->isPrototy ...
- [Flashback]开启数据库闪回数据库功能
Flashback是Oracle中一个重要的功能,想要使用闪回数据库功能,需要将数据库置于闪回数据库的状态. 1.检查数据库是否开启归档状态 SQL> archive log list; Dat ...
- Java基础差,需要怎么补
本文首发于本博客 猫叔的博客,转载请申明出处 感谢sugar的提问:Java基础差,需要怎么补? 欢迎关注公众号:Java猫说 我整体的总结了一下,大致分为以下的几个点说一下: 1.善于使用搜索引擎 ...
- Java多线程知识整理
多线程 1. 多线程基础 多线程状态转换图 普通方法介绍 yeild yeild,线程让步.是当前线程执行完后所有线程又统一回到同一起跑线.让自己或者其他线程运行,并不是单纯的让给其他线程. join ...
- Windows下配置Git多账号github码云
Windows下配置Git多账号github码云 1.配置了全局用户名和邮箱 $ git config --global user.email "你的邮箱" $ git confi ...
- 一个基于OCV的人肉选取特征点程序
基于OpenCV写了一个交互式获取图片上的人肉选取的特征,并保存到文件的小程序. 典型应用场景:当在一个精度不高的应用需求中,相机分辨率差或者变形严重,某些棋盘点通过代码检测不出,就可以通过手工选取的 ...
- Win10系统下装Ubuntu虚拟机的遇到的问题总结
环境和工具 win10操作系统 VMware Workstation 12 Ubuntu 14.0 64位 教程可参考:VMware Ubuntu安装详细过程(非常靠谱) [因为我的安装过程不是十分顺 ...