180731 浏览器底层原理 虚拟DOM

虚拟DOM是为了优化浏览器性能而设计的解决方案。当有多个DOM节点需要更新时,传统方式会导致多次昂贵的页面重绘。虚拟DOM通过在内存中操作JS对象模拟DOM,减少实际DOM操作,仅在最后将更新映射到真实DOM,从而避免不必要的计算,提高用户体验。本文介绍了虚拟DOM的基本概念和创建过程。

这里写图片描述

页面展示的步骤:

  1. 生成DOM树
  2. 生成CSS树
  3. 关联DOM树和CSS树,形成渲染树
  4. 浏览器布局
  5. 最后绘制

如果有10个需要更新的DOM节点,浏览器会依次执行10次以上流程。操作DOM的代价是昂贵的,频繁操作还是会出现页面卡顿,影响用户的体验。

虚拟DOM就是为了解决这个浏览器性能问题而被设计出来的。假如一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性attach到DOM树上,通知浏览器去执行绘制工作,这样可以避免大量的无谓的计算量。

用js对象来模拟DOM节点如下:

const tree = Element('div', { id: 'virtual-container' }, [
    Element('p', {}, ['Virtual DOM']),
    Element('div', {}, ['before update']),
    Element('ul', {}, [
        Element('li', { class: 'item' }, ['Item 1']),
        Element('li', { class: 'item' }, ['Item 2']),
        Element('li', { class: 'item' }, ['Item 3']),
    ]),
]);

const root = tree.render();
document.getElementById('virtualDom').appendChild(root);

用js对象模拟DOM节点的好处是,页面的更新可以先全部反映在js对象上,操作内存中的js对象的速度显然要快多了。等更新完后,再将最终的js对象映射成真实的DOM,交由浏览器去绘制。

那具体怎么实现呢?看一下Element方法的具体实现:

function Element(tagName, props, children) {
    if (!(this instanceof Element)) {
        return new Element(tagName, props, children);
    }

    this.tagName = tagName;
    this.props = props || {};
    this.children = children || [];
    this.key = props ? props.key : undefined;

    let count = 0;
    this.children.forEach((child) => {
        if (child instanceof Element) {
            count += child.count;
        }
        count++;
    });
    this.count = count;
}

第一个参数是节点名(如div),第二个参数是节点的属性(如class),第三个参数是子节点(如ul的li)。除了这三个参数会被保存在对象上外,还保存了key和count。

有了js对象后,最终还需要将其映射成真实的DOM:

Element.prototype.render = function() {
    const el = document.createElement(this.tagName);
    const props = this.props;

    for (const propName in props) {
        setAttr(el, propName, props[propName]);
    }

    this.children.forEach((child) => {
        const childEl = (child instanceof Element) ? child.render() : document.createTextNode(child);
        el.appendChild(childEl);
    });

    return el;
};

上面都是自解释代码,根据DOM名调用源生的createElement创建真实DOM,将DOM的属性全都加到这个DOM元素上,如果有子元素继续递归调用创建子元素,并appendChild挂到该DOM元素上。这样就完成了从创建虚拟DOM到将其映射成真实DOM的全部工作。

https://www.jianshu.com/p/616999666920

### 虚拟DOM原理、工作方式、优缺点及在前端开发中的作用 #### 什么是虚拟DOM虚拟DOM(Virtual DOM)是JavaScript对象的一种抽象表示,用于描述真实DOM的状态。它通过将真实的DOM节点转换为轻量级的JavaScript对象树结构,从而避免直接操作浏览器DOM[^3]。 #### 虚拟DOM的工作原理 虚拟DOM的工作流程主要包括以下几个阶段: 1. **构建虚拟DOM树**:当用户定义了组件或模板时,Vue会将其解析为一个虚拟DOM树,这是一个由JavaScript对象组成的树形结构。 2. **差异计算(Diff算法)**:当数据发生变化时,Vue会生成一个新的虚拟DOM树,并与旧的虚拟DOM树进行比较,找出需要更新的部分。 3. **更新真实DOM**:根据差异结果,Vue只对真实DOM中发生变化的部分进行最小化更新,而不是重新渲染整个页面[^1]。 以下是一个简单的虚拟DOM示例: ```javascript const virtualDom = { type: 'div', props: { id: 'container', className: 'box' }, children: [ { type: 'span', props: {}, children: ['Hello World'] } ] }; ``` #### 虚拟DOM的优点 1. **性能优化**:通过最小化真实DOM的操作,虚拟DOM能够显著减少浏览器重绘和回流的次数,从而提升性能[^3]。 2. **无需手动操作DOM**:开发者只需关注数据的变化,框架会自动根据虚拟DOM和数据绑定机制更新视图[^3]。 3. **跨平台支持**:由于虚拟DOM是JavaScript对象,它可以在不同平台上运行,例如服务器端渲染或移动应用开发(如Weex)[^5]。 #### 虚拟DOM的缺点 1. **首次渲染较慢**:由于需要将虚拟DOM转换为真实DOM,首次渲染可能会比直接使用`innerHTML`插入内容稍慢[^4]。 2. **内存消耗增加**:虚拟DOM需要额外的内存来存储节点树,这可能会影响页面加载时的内存使用情况[^4]。 3. **不适用于所有场景**:对于需要频繁直接操作DOM的应用(如某些游戏或图形密集型应用),虚拟DOM可能不是最佳选择[^4]。 #### 虚拟DOM在前端开发中的作用 虚拟DOM在现代前端开发中扮演着重要角色。它不仅简化了复杂的DOM操作,还提供了高效的视图更新机制。通过虚拟DOM,开发者可以专注于业务逻辑,而不必担心底层DOM操作细节[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值