虚拟DOM

浏览器渲染流程

file.png
  1. 解析HTML生成DOM树

  2. 解析CSS生成CSSOM树

  3. 将DOM树跟CSSOM树合成渲染树

  4. 遍历渲染树开始布局,计算每个节点的位置大小信息(重排发生之处)

  5. 绘制节点到屏幕(重绘)

js操作真实DOM的代价

虽然DOM是由JavaScript实现的,但是在浏览器中,DOM与JavaScript是分开来实现的。所以每一次通过js来操作DOM,都需要去链接js跟DOM。可以这样设想,js跟DOM是两个独立的城市,每一次操作,都是由js到达DOM,代价就是中间的路费,还有操作的费用。而越是频繁操作,代价越大。比如,有10个js更新DOM的操作,当第一个DOM请求操作发生的时候,浏览器不知道后面还有9次请求操作,DOM会马上走一个渲染流程。接着下一个请求操作,这个节点已经发生了改变,前一次的计算是无用功了,计算DOM节点的属性等都是白白浪费性能。

虚拟DOM

  1. 构建虚拟DOM树
  2. 元素发生更改,生成一颗新的DOM树,对比旧的DOM树,找到差异点
  3. 把差异点应用到真实DOM上去,实现局部替换

为什么需要虚拟DOM

可以解决js频繁操作DOM产生的性能问题。因为DOM的多次的操作不会立即操作DOM,而是会先反应到js对象(新的DOM树)上,通过比较,找到差异点,然后将差异的地方应用到真实DOM上去渲染,然后更新内存的DOM树(对象)。这样就避免了大量的无谓的过时的计算。

实现虚拟DOM

function virtualDOM (tag, props, children) {
    if (!this instanceof virtualDOM) {
        return new virtualDOM(tag, props, children)
    }
    this.tag = tag;
    this.props = props || {};
    this.children = children || [];
    this.key = props ? props.key : undefined;
    
    let count = 0;
    this.children.forEach((child) => {
        if (child instanceof virtualDOM) {
            count += child.count;
        }
        count++;
    });
    this.count = count;
}

virtualDOM.prototype.render = function() {
    const el = document.createElement(this.tag);
    const props = this.props;
    for (const prop in props) {
        el.setAttribute(prop, props[prop])
    }
    
    this.children.forEach((child) => {
        const childEle = (child instanceof virtualDOM) ? 
              child.render : document.createElement(child.tag);
        el.appendChild(childEle);
    })
    return el;
}

你可能感兴趣的:(虚拟DOM)