虚拟DOM

由状态到UI

状态

状态可以是JavaScript中的任意类型。Object、Array、String、Number、Boolean等都可以作为状态,这些状态可能最终会以段落、表单、链接或按钮等元素呈现在用户界面上,具体地说是呈现在页面上

渲染

本质上,我们将状态作为输入,并生成DOM输出到页面上显示出来,这个过程叫作渲染

在Web开发的早期,因为网页的展现十分简陋,我们所维护的状态也十分的简单,我们大可以直接操作DOM来进行开发,然而随着时代的发展,我们所开发的web也变的十分复杂,维护的状态也十分的多,DOM操作也十分频繁

命令式操作DOM

随着开发的深入,我们会发现在我们的项目中存在着大量用于操作DOM的代码,这种由我们直接通过代码来操作DOM的开发方法被称为命令式操作DOM

这些代码难以复用,所用到的状态也很难管理,会导致整个项目的逻辑变得十分混乱

声明式操作DOM

幸运的是,现代的主流框架,如vue,react,angular等都支持声明式操作DOM

声明式操作DOM即我们只用声明状态,通过模板或者其他方式来描述状态与视图的关系,框架就能帮我们渲染视图

自此,我们不再需要手动的操作DOM,统一由框架来操作DOM也能获得更好地渲染效率

事实上,并不是因为框架的出现web才有了状态,任何应用本就具有状态,只不过现代框架揭露了一个事实:我们的精力应该放在状态上,而不是如何将状态变成视图

效率的取舍

框架的设计处处充斥着权衡的艺术

假设我们将直接操作DOM的性能损耗设为A

div.innerHTML = "hello world"

那么通过声明式操作DOM的性能损耗为A+B

<div>{{ hello world }}</div>

因为框架不仅需要直接修改,而且还需要找出差异,所以声明式的代码性能并不优于命令式代码,但声明式代码的可维护性高,效果直观,而且我们可以通过各种手段来提升声明式代码的性能

但是需要注意的是,声明式代码本就依托于命令式代码,所以声明式代码优化也只能在寻找差异步骤处优化,再怎么优化性能也不会比命令式代码性能高效

虚拟DOM

理论上,用户的任何操作都有可能造成状态的改变,当状态改变时我们就需要重新渲染,直接操作DOM向来是简单且直接的,我们大可以将现有的DOM直接删除,然后重新根据现有状态来生成一个DOM,但是访问DOM是非常昂贵的。按照上面说的方式做,会造成相当多的性能浪费。状态变化通常只有有限的几个节点需要重新渲染,所以我们不仅需要找出哪里需要更新,还需要尽可能少地访问DOM
如何在找出哪里需要更新并且最大限度的减少DOM的访问,各家框架都有自己的一套解决方案,angular是脏检查的流程,react是虚拟DOM,vue1是细粒度的绑定,但从vue2开始就变成了虚拟DOM

虚拟DOM的解决方式是通过状态生成一个虚拟节点树,然后使用虚拟节点树进行渲染。在渲染之前,会使用新生成的虚拟节点树和上一次生成的虚拟节点树进行对比,只渲染不同的部分

虚拟DOM
在vue中,我们使用模板来描述状态与DOM之间的映射关系。vue通过编译将模板转换成渲染函数(render),执行渲染函数就可以得到一个虚拟节点树,使用这个虚拟节点树就可以渲染页面

render

VNode

VNode是vue中的一个类,通过new Vnode来生成虚拟节点,我们所谓的虚拟节点,本质上就是一个js对象,所谓的虚拟DOM树,就是由一个个js对象构成

在vue中,VNode的类型有以下几种

  1. 注释节点
  2. 文本节点
  3. 元素节点
  4. 组件节点
  5. 函数式组件
  6. 克隆节点

由于vue对组件采用了虚拟DOM来更新视图,当属性发生变化时,整个组件都要进行重新渲染的操作,但组件内并不是所有DOM节点都需要更新,所以将vnode缓存并将当前新生成的vnode和上一次缓存的oldVnode进行对比,只对需要更新的部分进行DOM操作可以提升很多性能

Patch

对两个虚拟节点进行比对是虚拟DOM中最核心的算法(即patch),它可以判断出哪些节点发生了变化,从而只对发生了变化的节点进行更新操作,具体关于patch的文章可以看我这篇博客
未动笔,未来可寄

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值