JS开销和如何缩短解析时间
代码解决方案
- Code splitting代码拆分,按需加载
- Tree shaking代码减重
减少主线程工作量
- 避免长任务
- 避免超过1KB的行间脚本
- 使用rAF(requestAnimationFrame)和rIC(requestIdleCallback)进行时间调度
逐步引导(progressive bootstrapping)
- 可见不可交互vs最小可交互资源集
配合V8有效优化代码
抽象语法树
- 源码 => 抽象语法树 => 字节码Bytecode => 机器码
- 编译过程会进行优化
- 运行时可能发生反优化
V8优化机制
- 脚本流
- 字节码缓存
- 懒解析
函数优化
- lazy parsing懒解析vs eager parsing饥饿解析 – (function Fn() {})
- 利用Optimize.js优化初次加载时间
对象优化
- 以相同顺序初始化对象成员,避免隐藏类型的调整
class RectArea { // HC0
constructor(l, w) {
this.l = l // HC1
this.w = w // HC2
}
}
const rect1 = new RectArea(3, 4)
const rect2 = new RectArea(5, 6)
// 隐藏类型无法复用
const car1 = {color: 'red'} // HC0
car1.seats = 4 // HC1
const car2 = {seats: 2} // HC2
car1.color = 'blue' // HC3
- 实例化后避免添加新属性
const car1 = {color: 'red'} // In-object属性
car1.seats = 4 // Normal/Fast属性,存储property store里,需要通过描述数组间接查找
- 尽量使用Array代替array-like对象
Array.prototype.forEach.call(arrObj, (value, index) => { // 不如在真实数组上效率高
console.log(`${index}:${value}`)
})
const arr = Array.prototype.slice.call(arrObj, 0) // 转换的代价比影响优化小
arr.forEach((value, index) => {
console.log(`${index}:${value}`)
})
- 避免读取超过数组的长度
function foo(array) {
for(let i = 0; i <= array.length; i++) { // 越界比较
if(array[i] > 1000){ // 1、造成undefined跟数字比较 2、沿原型链的查找
console.log(array[i]) // 业务上无效
}
}
}
- 避免元素类型转换
const array = [3, 2, 1] // PACKED_SMI_ELEMENTS
array.push(4.4) // PACKED_DOUBLE_ELEMENTS
HTML优化
- 减少iframes使用
- 压缩空白符
- 避免节点深层级嵌套
- 避免table布局
- 删除注释
- CSS&JavaScript尽量外链
- 删除元素默认属性
借助工具
- html-minifier
CSS优化
- 降低CSS对渲染的阻塞
- 利用GPU进行完成动画
- 使用contain属性
- 使用font-display属性