高效操作DOM(1)

197 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

啥是DOM

DOM(Document Object Model,文档对象模型),可以理解为接口,提供给JavaScript用来操作HTML,是前端的入门知识,同样也是核心内容,大部分前端功能都需要借助DOM来实现。

  • 动态渲染列表、表格表单数据;
  • 监听点击、提交事件;
  • 懒加载一些脚本或样式文件;
  • 实现动态展开树组件,表单组件级联等这类复杂的操作。

DOM操作很耗时

浏览器包含渲染引擎(也称浏览器内核)和 JavaScript 引擎,它们都是单线程运行。单线程的优势是开发方便,避免多线程下的死锁、竞争等问题,劣势是失去了并发能力。

为什么设计成单线程?

浏览器为了避免两个引擎同时修改页面而造成渲染结果不一致的情况,增加了另外一个机制,这两个引擎具有互斥性,也就是说在某个时刻只有一个引擎在运行,另一个引擎会被阻塞。比如:两个线程同时操作一个DOM,DOM要听谁的?

ju li

当操作DOM时会造成渲染引擎和JavaScript引擎线程之间的切换,切换是非常耗时的。如果频繁地大量切换,那么就会产生性能问题。 比如:

// 测试次数:一百万次
const times = 1000000
// 缓存body元素
console.time('object')
let body = document.body
// 循环赋值对象作为对照参考
for(let i=0;i<times;i++) {
  let tmp = body
}
console.timeEnd('object')// object: 1.77197265625ms
console.time('dom')
// 循环读取body元素引发线程切换
for(let i=0;i<times;i++) {
  let tmp = document.body
}
console.timeEnd('dom')// dom: 18.302001953125ms

重排(Reflow)与重绘(Repaint)

浏览器在渲染页面时会将 HTML 和 CSS 分别解析成 DOM 树和 CSSOM 树,然后合并进行排布,再绘制成我们可见的页面。如果在操作 DOM 时涉及到元素、样式的修改,就会引起渲染引擎重新计算样式生成 CSSOM 树,同时还有可能触发对元素的重新排布(简称“重排”)和重新绘制(简称“重绘”)。

重排+重绘

会影响到其他元素排布的操作:

  • 修改元素边距、大小
  • 添加、删除元素
  • 改变窗口大小

只是重绘:

只影响自身

  • 设置背景图片
  • 修改字体颜色
  • 改变 visibility 属性值