Web性能总结之DOM

本篇文档主要总结使用 DOM API 创建、访问、修改 DOM 元素的一些常见优化案例和对比效果

什么是 DOM

DOM 的全称是 Document Object Model,中文意思是文档对象模型,在浏览器中,主要用来与 HTML 打交道并使用 DOM API 来访问文档中的数据。

DOM 的访问与修改

如下代码,我们访问 p 标签并每次设置该标签的值,然后在 Chrome 下 执行 performance 分析过程,发现一个这段代码居然执行了 695ms,我们知道 JavaScript 中当一个任务执行超过 60ms 就属于是一个 Long Task 了,他会拖慢我们 Web 应用的性能,由此可见我们使用 DOM API 操作 DOM 的代价是非常昂高贵的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
</head>
<body>
<p></p>
<script>
window.onload = function () {
for (let i = 0; i <= 1000; i++) {
document.querySelector('p').innerHTML += '1';
}
}
</script>
</body>
</html>

img

高性能的访问与修改

在实际的工作中我们无法避免访问 DOM 和修改 DOM,那针对这种情况如何优化呢?有两个基本的黄金法则:1、缓存 DOM 对象;2、减少修改的频率,我们优化代码后可以看到这段脚本的执行时间变成了 2ms

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
</head>
<body>
<p></p>
<script>
window.onload = function () {
const elem = document.querySelector('p');
let res = '';
for (let i = 0; i <= 10000; i++) {
res += '1';
}
elem.innerHTML = res;
}
</script>
</body>
</html>

img

DOM 的创建

如下的代码,我们有一个列表 1000 项,需要展示到页面上,我们依次创建元素然后设置内容添加到页面中,再次运行 performance 分析发现,一个这么简单的任务居然执行了 58ms

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
</head>
<body>
<ul></ul>
<script>
window.onload = function () {
const data = new Array(1000).fill(Date.now());
const ul = document.querySelector('ul');
for (let i = 0; i < data.length; i++) {
const li = document.createElement('li');
li.innerHTML = data[i];
ul.appendChild(li);
}
}
</script>
</body>
</html>

img

高性能的 DOM 创建

尽管在现代的 Web 浏览器中存在优化机制会合并一些重排操作,但是我们一旦不注意编码的话就会被坑,针对这种情况我们可以减少重绘和重排的次数,我们使用文档片段优化后整体的时间降低至 34ms

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
</head>
<body>
<ul></ul>
<script>
window.onload = function () {
const data = new Array(1000).fill(Date.now());
const ul = document.querySelector('ul');
const fragment = document.createDocumentFragment();
for (let i = 0; i < data.length; i++) {
const li = document.createElement('li');
li.innerText = data[i];
fragment.appendChild(li);
}
ul.appendChild(fragment);
}
</script>
</body>
</html>

img