【JS】前端性能优化(二)

前端性能优化" title="前端性能优化">前端性能优化(二)

huangsh发布于 今天 07:36

运行时性能优化

1.减少重绘重排

浏览器渲染过程

  1. 解析HTML生成DOM树;
  2. 解析CSS生成CSSOM规则树;
  3. 将DOM树与CSSOM规则树合并在一起生成渲染树;
  4. 遍历渲染树开始布局,计算DOM节点的大小和位置;
  5. 调用GPU绘制,合成图层;
  6. 将渲染树每个节点绘制到屏幕。

【JS】前端性能优化(二)

重排

当改变DOM元素位置或大小时,会导致浏览器重新生成渲染树,这个过程叫重排。

重绘

当重新生成渲染树render tree后,就要将渲染树每个节点绘制到屏幕,这个过程叫重绘。不是所有动作都会导致重排,例如改变字体颜色,只会导致重绘。重排会导致重绘,重绘不会导致重排。

重排和重绘这两个操作都是非常昂贵的,因为Javascript引擎线程与GUI渲染线程是互斥的,它们同时只能一个在工作。

什么操作会导致重排

  • 添加或删除DOM元素
  • 改变元素的位置
  • 改变元素的大小
  • 元素内容的改变
  • 浏览器窗口尺寸的改变

如何减少重绘重排

  • 用js修改样式时,用class来修改,而不是直接用js来修改样式;
  • 如果要对 DOM 元素执行一系列操作,可以将 DOM 元素脱离文档流,修改完成后,再将它带回文档。推荐使用隐藏元素(display:none)或文档碎片(DocumentFragement),都能很好的实现这个方案。

2.使用事件委托

事件委托利用了事件冒泡的原理,只制定一个事件处理程序,就可以管理某一类型的所有事件。多数鼠标事件和键盘事件都合适采用事件委托技术,使用事件委托可以节省内存。

// good 使用事件委托

const ul = document.querySelector('ul')

ul.onclick = (e) => {

const target = e.target

if (target.nodeName === 'LI') {

console.log(target.innerText)

}

}

// bad 没有使用事件委托,事件直接绑定在li上

document.querySelector('li').forEach((e) => {

e.target.onclick = function () {

console.log(this.innerText)

}

})

3.if-else 对比 switch

if (name === '张三') {

} else if (name === '李四') {

} else if (name === '王五') {

} else if (name === '赵六') {

} else if (name === '钱七') {

}

// 使用switch

swith (name) {

case '张三':

break

case '李四':

break

case '王五':

break

case '赵六':

break

case '钱七':

break

}

以上这种情况,使用switch比较好。假设name值为钱七,if-else要经过5次判断,而switch只需要进行一次。

4.查找字典表

继续上面的例子,当条件语句特别多时,使用if-else和switch都不是最佳选择,这时可以用字典表:

const map = {

'张三': result1,

'李四': result2,

'王五': result2,

'赵六': result2,

'钱七': result2,

}

return map[name]

5.使用requestAnimationFrame来实现视觉变化

我们知道,大多数设备屏幕的刷新率为60次/秒,也就是说每一帧的平均时间为16.6毫秒。在使用Javascript实现动画效果的时候,最好的情况就是每次代码都在帧的开头开始执行。而保证Javascript在帧开始运行的唯一方式是使用requestAnimationFrame

function undateScreen() {

// 设置动画

...

}

window.requestAnimationFrame(undateScreen)

如果采取setTimeoutsetInterval来实现动画的话,回调函数将在帧中的某个时间点来运行,可能刚好在末尾,而这可能经常会使我们丢失帧,导致卡顿。
【JS】前端性能优化(二)

6.使用位操作

位操作比其他数学运算和布尔操作快得多。

取整

~~5.34  // 5

~~'5.34' // 5

~~undefined // 0

~~null // 0

7.不要覆盖原生方法

无论你的 JavaScript 代码如何优化,都比不上原生方法。因为原生方法是用 C/C++ 写的,并且被编译成机器码,成为浏览器的一部分。当原生方法可用时,尽量使用它们,特别是数学运算和 DOM 操作。

8.降低CSS选择器的复杂性

  • 浏览器读取CSS选择器,遵循的原则是从选择器的右边到左边读取。

#app .wrap div {

color: white;

}

1、查找所有div元素
2、查找结果1中的元素是否有类名为 wrap 的父元素
3、查找结果2中的元素是否有id为app的父元素

所以,可以得出结论:
1、选择器越短越好
2、尽量使用高优先级选择器
3、避免使用通配符 *

9.使用flex布局

flex布局要比早期的浮动、相对定位和绝对定位布局性能要好。

10.使用transfrom和opacity属性更改来实现动画

在CSS中,transform和opacity这两个属性更改不会触发重排与重绘,他们是可以由合成器单独处理的属性。

javascriptjquery前端react.jsvue.js

阅读 48发布于 今天 07:36

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议


前端--风雨开发路

用心整理web前端开发过程中遇到的坑和绕过的弯,希望能帮助到茫茫人海中的你!

avatar

huangsh

灵魂和皮囊能够握手言和,面子和里子能够始终如一。

110 声望

4 粉丝

0 条评论

得票时间

avatar

huangsh

灵魂和皮囊能够握手言和,面子和里子能够始终如一。

110 声望

4 粉丝

宣传栏

运行时性能优化

1.减少重绘重排

浏览器渲染过程

  1. 解析HTML生成DOM树;
  2. 解析CSS生成CSSOM规则树;
  3. 将DOM树与CSSOM规则树合并在一起生成渲染树;
  4. 遍历渲染树开始布局,计算DOM节点的大小和位置;
  5. 调用GPU绘制,合成图层;
  6. 将渲染树每个节点绘制到屏幕。

【JS】前端性能优化(二)

重排

当改变DOM元素位置或大小时,会导致浏览器重新生成渲染树,这个过程叫重排。

重绘

当重新生成渲染树render tree后,就要将渲染树每个节点绘制到屏幕,这个过程叫重绘。不是所有动作都会导致重排,例如改变字体颜色,只会导致重绘。重排会导致重绘,重绘不会导致重排。

重排和重绘这两个操作都是非常昂贵的,因为Javascript引擎线程与GUI渲染线程是互斥的,它们同时只能一个在工作。

什么操作会导致重排

  • 添加或删除DOM元素
  • 改变元素的位置
  • 改变元素的大小
  • 元素内容的改变
  • 浏览器窗口尺寸的改变

如何减少重绘重排

  • 用js修改样式时,用class来修改,而不是直接用js来修改样式;
  • 如果要对 DOM 元素执行一系列操作,可以将 DOM 元素脱离文档流,修改完成后,再将它带回文档。推荐使用隐藏元素(display:none)或文档碎片(DocumentFragement),都能很好的实现这个方案。

2.使用事件委托

事件委托利用了事件冒泡的原理,只制定一个事件处理程序,就可以管理某一类型的所有事件。多数鼠标事件和键盘事件都合适采用事件委托技术,使用事件委托可以节省内存。

// good 使用事件委托

const ul = document.querySelector('ul')

ul.onclick = (e) => {

const target = e.target

if (target.nodeName === 'LI') {

console.log(target.innerText)

}

}

// bad 没有使用事件委托,事件直接绑定在li上

document.querySelector('li').forEach((e) => {

e.target.onclick = function () {

console.log(this.innerText)

}

})

3.if-else 对比 switch

if (name === '张三') {

} else if (name === '李四') {

} else if (name === '王五') {

} else if (name === '赵六') {

} else if (name === '钱七') {

}

// 使用switch

swith (name) {

case '张三':

break

case '李四':

break

case '王五':

break

case '赵六':

break

case '钱七':

break

}

以上这种情况,使用switch比较好。假设name值为钱七,if-else要经过5次判断,而switch只需要进行一次。

4.查找字典表

继续上面的例子,当条件语句特别多时,使用if-else和switch都不是最佳选择,这时可以用字典表:

const map = {

'张三': result1,

'李四': result2,

'王五': result2,

'赵六': result2,

'钱七': result2,

}

return map[name]

5.使用requestAnimationFrame来实现视觉变化

我们知道,大多数设备屏幕的刷新率为60次/秒,也就是说每一帧的平均时间为16.6毫秒。在使用Javascript实现动画效果的时候,最好的情况就是每次代码都在帧的开头开始执行。而保证Javascript在帧开始运行的唯一方式是使用requestAnimationFrame

function undateScreen() {

// 设置动画

...

}

window.requestAnimationFrame(undateScreen)

如果采取setTimeoutsetInterval来实现动画的话,回调函数将在帧中的某个时间点来运行,可能刚好在末尾,而这可能经常会使我们丢失帧,导致卡顿。
【JS】前端性能优化(二)

6.使用位操作

位操作比其他数学运算和布尔操作快得多。

取整

~~5.34  // 5

~~'5.34' // 5

~~undefined // 0

~~null // 0

7.不要覆盖原生方法

无论你的 JavaScript 代码如何优化,都比不上原生方法。因为原生方法是用 C/C++ 写的,并且被编译成机器码,成为浏览器的一部分。当原生方法可用时,尽量使用它们,特别是数学运算和 DOM 操作。

8.降低CSS选择器的复杂性

  • 浏览器读取CSS选择器,遵循的原则是从选择器的右边到左边读取。

#app .wrap div {

color: white;

}

1、查找所有div元素
2、查找结果1中的元素是否有类名为 wrap 的父元素
3、查找结果2中的元素是否有id为app的父元素

所以,可以得出结论:
1、选择器越短越好
2、尽量使用高优先级选择器
3、避免使用通配符 *

9.使用flex布局

flex布局要比早期的浮动、相对定位和绝对定位布局性能要好。

10.使用transfrom和opacity属性更改来实现动画

在CSS中,transform和opacity这两个属性更改不会触发重排与重绘,他们是可以由合成器单独处理的属性。

以上是 【JS】前端性能优化(二) 的全部内容, 来源链接: utcz.com/a/113435.html

回到顶部