您的位置: 翼速应用 > 业内知识 > web前端 > 正文

React中的Virtual DOM

123456.png

什么是虚拟DOM

本质上是 Javascript 对象,是对DOM更加轻量级的描述。

起源

React是由facebook开发,其中的Virtual DOM自然也离不开facebook的影子。

字符串拼接时代 - 2004

动态页面需要根据用户的操作不断的对页面进行渲染,这就需要后端的支持,此时,大家还都是在用PHP的字符串拼接开发网站。

$str = '<ul>';
foreach ($talks as $talk) {
  $str += '<li>' . $talk->name . '</li>';
}
$str += '</ul>';

代码不优雅,容易出现XSS攻击,较差的用户体验都是这种方法存在的问题。

XHP 时代 - 2010

到了 2010 年,为了更加高效的编码,同时也避免转义 HTML 标签的错误,Facebook 开发了 XHP 。XHP 是对 PHP 的语法拓展,它允许开发者直接在 PHP 中使用 HTML 标签,而不再使用字符串。

$content = <ul />;
foreach ($talks as $talk) {
  $content->appendChild(<li>{$talk->name}</li>);
}

JSX - 2013

到了 2013 年,前端工程师 Jordan Walke 向他的经理提出了一个大胆的想法:把 XHP 的拓展功能迁移到 JS 中。首要任务是需要一个拓展来让 JS 支持 XML 语法,该拓展称为 JSX。因为当时由于 Node.js 在 Facebook 已经有很多实践,所以很快就实现了 JSX。

const content = (
  <TalkList>
    { talks.map(talk => <Talk talk={talk} />)}
  </TalkList>
);

React - Now

在这个时候,就有另外一个很棘手的问题,那就是在进行更新的时候,需要去操作 DOM,传统 DOM API 细节太多,操作复杂,所以就很容易出现 Bug,而且代码难以维护。

然后就想到了 PHP 时代的更新机制,每当有数据改变时,只需要跳到一个由 PHP 全新渲染的新页面即可。

从开发者的角度来看的话,这种方式开发应用是非常简单的,因为它不需要担心变更,且界面上用户数据改变时所有内容都是同步的。

为此 React 提出了一个新的思想,即始终整体“刷新”页面

当发生前后状态变化时,React 会自动更新 UI,让我们从复杂的 UI 操作中解放出来,使我们只需关于状态以及最终 UI 长什么样。

局部刷新:

// 下面是伪代码
var ul = find(ul) // 先找到 ul
ul.append(`<li>${message3}</li>`) //然后再将message3插到最后

// 想想如果是不插到最后一个,而是插到中间的第n个
var ul = find(ul) // 先找到 ul
var preli = find(li(n-1)) // 再找到 n-1 的一个 li
preli.next(`<li>${message3}</li>`) // 再插入到 n-1 个的后面

整体刷新:

UI = f(messages) // 整体刷新 3 条消息,只需要调用 f 函数

// 这个是在初始渲染的时候就定义好的,更新的时候不用去管
function f(messages) {
	return<ul>
		{messages.map(message => <li>{ message }</li>)}
	</ul>
}

整体刷新虽然让我们忽略了操作DOM的细节,但是却带来了性能差的问题。

Diff

有人便想到了使用版本控制的思想解决上述问题,先对比前后变化的差异,再进行刷新。

Virtual DOM

做过 JS 应用优化的人可能都知道,DOM 是复杂的,对它的操作(尤其是查询和创建)是非常慢非常耗费资源的。看下面的例子,仅创建一个空白的 div,其实例属性就达到 231 个。

// Chrome v63
const div = document.createElement('div');
let m = 0;
for (let k in div) {
  m++;
}
console.log(m); // 231

对于 DOM 这么多属性,其实大部分属性对于做 Diff 是没有任何用处的,所以如果用更轻量级的 JS 对象来代替复杂的 DOM 节点,然后把对 DOM 的 diff 操作转移到 JS 对象,就可以避免大量对 DOM 的查询操作。这个更轻量级的 JS 对象就称为 Virtual DOM 。

那么现在的过程就是这样:

  1. 维护一个使用 JS 对象表示的 Virtual DOM,与真实 DOM 一一对应
  2. 对前后两个 Virtual DOM 做 diff ,生成变更(Mutation)
  3. 把变更应用于真实 DOM,生成最新的真实 DOM

可以看出,因为要把变更应用到真实 DOM 上,所以还是避免不了要直接操作 DOM ,但是 React 的 diff 算法会把 DOM 改动次数降到最低。

总结

传统前端的编程方式是命令式的,直接操纵 DOM,告诉浏览器该怎么干。这样的问题就是,大量的代码被用于操作 DOM 元素,且代码可读性差,可维护性低。

React 的出现,将命令式变成了声明式,摒弃了直接操作 DOM 的细节,只关注数据的变动,DOM 操作由框架来完成,从而大幅度提升了代码的可读性和可维护性。

在初期我们可以看到,数据的变动导致整个页面的刷新,这种效率很低,因为可能是局部的数据变化,但是要刷新整个页面,造成了不必要的开销。

所以就有了 Diff 过程,将数据变动前后的 DOM 结构先进行比较,找出两者的不同处,然后再对不同之处进行更新渲染。

但是由于整个 DOM 结构又太大,所以采用了更轻量级的对 DOM 的描述—虚拟 DOM。

不过需要注意的是,虚拟 DOM 和 Diff 算法的出现是为了解决由命令式编程转变为声明式编程、数据驱动后所带来的性能问题的。换句话说,直接操作 DOM 的性能并不会低于虚拟 DOM 和 Diff 算法,甚至还会优于。



我来说两句

0 条评论

推荐阅读

  • 响应式布局CSS媒体查询设备像素比介绍

    构建响应式网站布局最常见的是流体网格,灵活调整大小的站点布局技术,确保用户在使用的幕上获得完整的体验。响应式设计如何展示富媒体图像,可以通过以下几种方法。

    admin
  • 提升网站的性能快速加载的实用技巧

    网站速度很重要,快速加载的网站会带来更好的用户体验、更高的转化率、更多的参与度,而且在搜索引擎排名中也扮演重要角色,做SEO,网站硬件是起跑线,如果输在了起跑线,又怎么跟同行竞争。有许多方法可提升网站的性能,有一些技巧可以避免踩坑。

    admin
  • 织梦CMS TAG页找不到标签和实现彩色标签解决方法

    织梦cms是我们常见的网站程序系统的一款,在TAG标签中常常遇到的问题也很多。当我们点击 tags.php 页的某个标签的时候,有时会提示:“系统无此标签,可 能已经移除!” 但是我们检查程序后台,以及前台显示页面。这个标签确实存在,如果解决这个问题那?

    admin
  • HTML关于fieldset标签主要的作用

    在前端开发html页面中常用的标签很多,今天为大家带来的是关于HTML中fieldset标签主要的作用说明,根据技术分析HTML

    admin

精选专题