前端操作 DOM ,为什么最耗性能?

2019-06-2909:38:08WEB前端开发Comments2,694 views字数 1189阅读模式

不一定文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

  1. 预备知识

我们看一下浏览器和 JS 引擎的关系(以 Chrome 和 V8 举例):文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

前端操作 DOM ,为什么最耗性能?
V8 binding between WebKit and V8

其他浏览器和 JS 引擎也大同小异。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

在 ECMAScript 规范中,Web IDL 定义了 DOM 和 JS Object 的对应关系:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

前端操作 DOM ,为什么最耗性能?
Web IDL、DOM、ECMAScript

通常而言,DOM 对象是使用 C++ 开发的,而通过 V8 Binding,在 V8 引擎内会有一个和 DOM 对象对应的 JS 对象,我们称之为Wrapper objects(包装对象)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

包装对象和原生对象的关系可能是 1 对 1,也可能是 n 对 1,但是会是 1 对 n。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

前端操作 DOM ,为什么最耗性能?
前端操作 DOM ,为什么最耗性能?

2. 为什么有时候 DOM 不慢文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

从上面的介绍可以看出,DOM 是 C++ 写的,性能肯定不慢。而且 V8 Binding 会把原生 DOM 对象映射为包装的 JS 对象。因此,我们操作 DOM 和操作 JS 对象是一样的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

我们以 document 为例。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

js 普通对象:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

let o = {a: 2};

console.time('js');
for(let i=0; i<=1e4; i++)
    o.a = i;
console.timeEnd('js');
// 耗时: 0.31396484375ms

document 对象:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

console.time('dom');
for(let i=0; i<=1e4; i++)
    document.a = i;
console.timeEnd('dom');
// 耗时: 0.302978515625ms

从上面的结果看,DOM 对象好像比 JS 普通对象还要快一些。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

3. DOM 为什么慢文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

现在我们把上面的测试代码改一下,把 document.a 改成 document.title文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

console.time('dom');
for(let i=0; i<=1e4; i++)
    document.title = i;
console.timeEnd('dom');
// 耗时: 128.337646484375ms

耗时突然变成了原来的 400 多倍。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

这是因为 JS 对象的属性(properties)映射到了 DOM 对象的特性(attributes)上。当我们修改 document.a 时,只是修改了普通的 JS 对象,但是在我们修改 document.title 的时候,同时也修改了 DOM 对象的 attributes。如果我们在 Chrome Devtool 运行这段代码,可以看到页面的标题在不停的改变,代码运行结束后,页面标题变成了 10000。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

性能消耗在 JS 对象和 DOM 对象的转换和同步。也就是 V8XXX::toNative()::toV8() 的调用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

4. CSS文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

浏览器除了具有 JS 引擎外,还有排版引擎。而如果 JS 在操作 DOM 时修改了 CSS,那么性能就会再一次降低文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

前端操作 DOM ,为什么最耗性能?

即使我们不修改 DOM 对象的 CSS,仅仅是读取样式值,也有可能会引起 relayout。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

5. GC文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

DOM 对象还会导致 GC 变复杂。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

前端操作 DOM ,为什么最耗性能?

虽然 DOM 的性能有可能比普通对象还快,但是在 99% 的场景下 DOM 对象是慢的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/13875.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/gcs/13875.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定