JavaScript的性能优化与调试技巧 | 青训营

55 阅读3分钟

一、减少重绘与重排

浏览器下载完成所有的html标记,js,css,图片之后,它解析文件并创建两个内部结构,一个是DOM树,一个是渲染树。浏览器根据DOM树来进行排列,根据渲染树来进行绘制。

  • 重绘就是重新绘制(repaint):当一个元素的外观被改变时所触发的浏览器行为,浏览器会根据元素的新属性重新进行绘制,使元素呈现新的外观。外观属性包括界面、文字等可用状态向量描述的属性。

  • 重排就是重新排列(reflow):当渲染树的一部分必须更新并且节点的尺寸发生了变化,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。改变元素几何信息(大小和位置)都会引起重排,比如:添加或删除可见的DOM元素,使用动画,元素的尺寸改变(外边距、内边距、边框厚度、宽高等几何属性),激活CSS伪类(如 :hover)等等。

为了减少重绘和重排,我们要避免一条一条的修改DOM的样式,避免把DOM结点的属性值放在一个循环里当成循环里的变量,避免在布局信息改变时查询布局信息,当需要对DOM元素进行一系列的操作时,可以先使元素脱离文档流。

const e = document.getElementById('myElement');
for (let i = 0; i < 100; i++) {
  e.style.left = i + 'px';
}

以上写法是在循环中修改样式属性或获取布局信息会频繁触发重绘重排,可以改为以下写法:

const e = document.getElementById('myElement');
e.classList.add('m1');

.m1 {
    left: 100px;
}

同样属性的访问将会导致重新刷新渲染树从而导致重排,最好减少对这些布局信息的查询次数,查询时将它赋给局部变量,并用局部变量参与计算。比如:

const e = document.getElementById('myElement');
e.style.left = '100px';
e.style.top = '100px';

这段代码改变了两次风格属性,导致浏览器重排了两次。我们可以进行以下修改使其只进行一次排列绘制:

const e = document.getElementById('myElement');
e.style.text = 'left:100px ; top:100px';

二、节流与防抖技术

  • 节流(thorttle):高频事件触发,每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法。
function throttle(fn, delay) {
  let timer;
  return function (...args) {
    if (!timer) {
      timer = setTimeout(() => {
        fn(...args);
        timer = null;
      }, delay);
    }
  }
}
  • 防抖(debounce):防抖触发高频率事件时n秒后只会执行一次,如果n秒内再次触发,则会重新计算。事件触发后开启定时器,如果在这个定时器时间内再次触发,则清除这个定时器,再写一个定时器。
function debounce(fn, delay){
	let timer;
	return function(...args){
		clearTimeout(timer);
		timer = setTimeout(()=> {
			fn(...args);
		}, delay)
	}
}

节流是将多次执行变成每隔一段时间执行,防抖是将多次执行变为最后一次执行。函数节流一段时间内只执行一次,函数防抖一定时间连续触发的事件,只在最后执行一次。

三、性能分析工具

性能分析工具可以帮助我们提供优化建议。

  • Chrome 开发者工具: Chrome 浏览器自带的开发者工具提供了强大的性能分析功能。功能简洁,速度快,运行稳定,插件扩展丰富,chrome有出色的兼容性,它能够很好的兼容HTML5和CSS3,我们可以使用它来检查网页加载性能、 JavaScript 代码执行时间以及内存占用等信息。

  • Lighthouse : Lighthouse是一个开源的自动化性能测试工具,我们可以使用该功能检测我们的页面存在哪些性能方面的问题,并会生成一个详细的性能报告来帮助我们来优化页面。Lighthouse 会衡量的 Metrics 性能指标项有:首次内容绘制(First Contentful Paint),首次有效绘制(First Meaningful Paint),首次 CPU 空闲(First CPU Idle),可交互时间(Time to Interactive),速度指标(Speed Index),输入延迟估值(Estimated Input Latency)。