关于前端性能优化的一些建议
日期:2021-06-10 18:30:00
更新:2021-06-10 18:30:00
标签:前端, JavaScript
分类:JavaScript
本文主要介绍性能优化的一些建议,包括编码,动画性能,页面启动性能优化
本文主要介绍性能优化的一些建议,包括编码,动画性能,页面启动性能优化
编码
避免全局查找
使用全局变量和函数要比局部的开销更大,可以将全局变量保存在局部的变量中,再去调用.
将在一个函数中多次调用的全局对象保存到局部变量总是没错的[1]
function updateElement() {
var p = document.getElementsByTagName('p');
var title = document.getElementById('title');
p.forEach(val => {
val.innerHTML = document.title;
})
title.innerHTML = 'world';
}
function updateElement() {
var doc = document;
var p = doc.getElementsByTagName('p');
var title = doc.getElementById('title');
p.forEach(val => {
val.innerHTML = doc.title;
})
title.innerHTML = 'world';
}
避免with语句
with语句相信大家都听说过。它会创建自己的作用域,因此会增加其中执行代码的作用域链长度,造成with语句中执行的代码会比外面执行的代码要慢。
避免不必要的属性查找
能减少算法的复杂度要尽量减少,尽可能地多使用局部变量将属性查找替换为值查找。
var a = 1;
var b = 100 + a;
console.log(b);
var arr = [1, 100];
var b = arr[0] + arr[1];
console.log(c);
上面两端代码执行效率是一样的
代码1它会进行4次常量查找,分别是:a,数字1,数字100,b,时间复杂度为O(1)
代码2的时间复杂度也是O(1)
若是用对象声明变量查找,他会比在数组上访问变量时间更长,比如
var obj = { a: 1, b: 100 };
var result = obj.b - obj.a;
console.log(result);
上面代码访问变量的时间复杂度为O(n),对象在查找时必须向原型链中搜索该属性,所以对象属性越多,查找时间越长。
简化循环终止条件
将循环终止的条件值放到声明变量中,避免属性查找或其他 O(n)的操作
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
for (let i = 0; i < arr.length; i ++) {
...
}
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
for (let i = 0, len = arr.length; i < len; i ++) {
...
}
避免双重解释
const code = `var a = 0; console.log(a)`;
eval(code);
var test = new Function(code);
setTimeout(code, 1000);
多个变量声明
代码语句数量也是会影响执行的操作的速度,完成多个操作的单个语句要比完成单个操作的多个语句快
var a = 1;
var b = 'a';
var c = {};
var d = [];
var a = 1,
b = 'a',
c = {},
d = [];
使用数组和对象字面量
从上面可以了解到单个操作的多个语句相对而言会比较快,因此在初始化对象或数组是,也可以这样做
var arr = [];
arr[0] = 'aaa';
arr[1] = 'bbb';
arr[2] = 'ccc';
var obj = {};
obj.a = 'aaa';
obj.b = 111;
obj.c = () => {};
var arr = ['aaa', 'bbb', 'ccc'];
var obj = {
a: 'aaa',
b: 111,
c: () => {},
}
优化DOM交互
最小化现场更新
浏览器中渲染界面是一个非常消耗性能的事情,所以减少频繁地插入DOM节点显得非常有必要。例如:
var list = document.getElementById('list');
for (let x = 0, max = 10, x < max; x++) {
var li = document.createElement('li');
li.innerHTML = x;
list.appendChild(li);
}
上面的代码会向list重复插入10个节点,每次插入节点,浏览器都会重新计算一次页面的位置。消耗非常大的性能。解决的办法就是使用createDocumentFragment
var list = document.getElementById('list');
var fragment = document.createDocumentFragment();
for (let x = 0, max = 10, x < max; x++) {
var li = document.createElement('li');
li.innerHTML = x;
fragment.appendChild(li);
}
list.appendChild(fragment);
使用文档片段改进后,只有一次插入节点的操作,有效减少节点更新造成的性能消耗。
除此之外,使用innerHTML也可以造成差不多的效果,但是字符串拼接会有一定的性能损失。
var list = document.getElementById('list');
var html = '';
for (let x = 0, max = 10, x < max; x++) {
html += `<li>${ x }</li>`;
}
list.innerHTML = html;
使用事件代理
由发布-订阅模式可以知道,随着监听器的增加,内存也会增加,使得页面性能变差。
在点击列表事件时,可以利用事件代理来减少监听器的声明。
var list = document.getElementsByTagName('li');
for(let x = 0, len = list.length; x < len; x++) {
list[x].onclick = () => {
...
}
}
var ul = document.getElementById('#ul');
ul.addEventListener('click', (e) => {
let target = e.target;
switch(target.id) {
case "li_1": .....
case "li_2": .....
}
});
优化启动性能
- 使用dns预获取文件
- 在需要异步执行的脚本使用
defer 或 async 属性加载。这可以让HTML解析器更高效地处理文档。
- 使用 Web workers 运行持续时间长的 JavaScript 代码逻辑
- 所有能并行的数据处理都应该并行化。不要一团接一团地处理数据,如果可能的话,同时处理它们
- 在你启动的HTML文件中,不要包含不会在关键路径下出现的脚本或样式表。只在需要时加载他们[2]
参考
- JavaScript高级程序设计
- web性能