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

60 阅读5分钟

性能优化与调试技巧

本文探讨如何通过优化JavaScript代码来提高性能,包括减少重绘和重排、使用节流和防抖技术、使用性能分析工具等;

常见的JavaScript性能问题

在进行JavaScript性能优化之前,我们需要了解一些常见的JavaScript性能问题。以下是一些常见的问题:

1.频繁的DOM访问:频繁地访问DOM元素可能会导致性能问题。因为访问DOM元素是非常昂贵的操作,它需要从浏览器中获取元素的引用并计算元素的位置和大小。

2.过多的HTTP请求:过多的HTTP请求会导致页面加载时间过长,从而影响用户体验。每次发送HTTP请求都需要建立TCP连接和传输数据,这些操作需要时间和资源。

3.大量的JavaScript文件:如果Web应用程序使用大量的JavaScript文件,那么加载时间会变得很长,从而影响用户体验。每个JavaScript文件都需要建立一个HTTP请求,并且需要解析和执行,这些操作都需要时间和资源。

4.内存泄漏:内存泄漏是指在代码中创建的对象无法被垃圾回收器正确地回收。如果JavaScript代码中存在内存泄漏,那么在长时间运行Web应用程序时,内存使用率可能会不断增加,从而导致性能问题。

减少重绘和重排

引起重排重绘的原因有:

  • 添加或者删除可见的DOM元素,
  • 元素尺寸位置的改变
  • 浏览器页面初始化,
  • 浏览器窗口大小发生改变,重排一定导致重绘,重绘不一定导致重排,

减少重绘重排的方法有:

  1. 在用js修改盒子的多个样式时,尽量使用className来一次性对盒子进行修改。
//一次性修改盒子的类名className
// css 
.active {
    padding: 5px;
    border-left: 1px;
    border-right: 2px;
}
// javascript
var el = document.querySelector('.el');
el.className = 'active';

// 或者修改cssText
var el = document.querySelector('.el');
el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px';
  1. 使用display:none让父盒子先消失,然后再对此盒子添加一些子元素,然后再将这个父盒子display:block显示出来。浏览器一共发生了两次重排,即第一次的隐藏和最后面的显示。中间的操作都不会造成重排。
  2. 使用文档片段createDocumentFragment创建一个子树,然后再拷贝到盒子中
let fragment = document.createDocumentFragment();
appendNode(fragment, data);  //这个过程相当于在这个文档碎片中添加一些子元素
ul.appendChild(fragment); //然后再将文档碎片子树添加到父盒子中
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
    </ul>
</body>
<script>
    let ul = document.querySelector("ul")
    let domFragment = document.createDocumentFragment() //创建文档碎片
    let arr = ["wh", "xx", "wmg", "lyh", "wws"]
    for (let i = 0; i < arr.length; i++) {
        let li = document.createElement("li")
        li.innerHTML = arr[i]
        domFragment.appendChild(li) //在文档碎片中添加元素
    }
    ul.appendChild(domFragment) //将这个碎片构成的dom子树添加到ul中
</script>

</html>

image.png

节流和防抖

节流和防抖严格意义上来说是属于性能优化领域的,实际上遇到的频率很高,如果不做防抖或者节流可能会出现bug或者页面卡死现象,使用防抖和节流可以节省大量不必要的开销。

对于短时间内连续触发的事件如滚动事件,关注最后结果只执行一次,防抖的定义是在某个时长内,事件处理函数执行一次。(连续触发的过程中只执行中最后一次,控制次数)

如何实现防抖

function debounce(fn,duration){
	let timer = null
    return function(){
        //在duration中存在计时器,则清空当前定时器,重新开始计时
        if(timer){
            clearTimeout(timer)
        }
        timer = setTimeout(fn,duration)
    }
}

防抖的应用场景

  • 鼠标滚动事件
  • 表单验证
  • 搜索栏搜索调用最后一次查询接口
  • 页面resize事件只关心最后一次页面渲染情况

什么是节流

再来思考,如果用户一直在执行滚动事件,时间间隔到在duration内,那就一直不会触发函数,这样也不行,我们需要在一段时间后让这个事件函数执行,节流的定义是函数执行一次后,在某个时长内短暂失效,等待时长过了之后该函数才能继续工作。(连续触发的过程中被定期执行,控制频率)

如何实现节流

//利用定时器实现
function throttle(fn,delay){
	let flag = true
    return function(){
        if(!flag) return
        flag = false
        setTimeout(() => {
            fn()
            flag = true
        },delay)
    }
}

//利用时间戳实现
function throttle1(fn,delay){
    let prevTime = 0
    return function(){
        if(new Date() - prevTime < delay) return
        fn()
        prevTime = new Date()
    }
}

节流的应用场景

搜索栏搜索定时调用接口

性能分析工具

性能分析工具可以帮助我们检测和优化JavaScript代码的性能,它们可以提供以下一些功能:

  • 记录和展示代码的执行过程和时间,比如主线程的事件循环、每个事件循环的任务、每个任务的调用栈、每个函数的耗时等。
  • 定位和高亮代码中的性能瓶颈和问题,比如内存泄露、过多的重绘和重排、低效的循环和函数等。
  • 提供一些优化建议和解决方案,比如使用缓存、节流和防抖、减少全局变量、使用直接量等。

Chrome DevTools 的 Performance 工具是Chrome浏览器内置的一个强大的工具,可以记录和展示网页的性能数据,包括JS代码、CSS样式、DOM操作、网络请求等。它还可以模拟不同的网络和CPU条件,以及提供一些优化建议。

Chrome DevTools 的 Performance 工具主要包括以下几个部分:

  • 概览部分,显示了整体的界面渲染情况,每个时间段执行的事件顺序,以及一些关键指标,如页面帧速 (FPS)、CPU 资源消耗、网络请求流量、V8 内存使用量 (堆内存) 等。
  • 性能面板部分,显示了渲染进程中各个线程的执行记录,包括主线程 (Main)、合成线程 (Compositor)、光栅化线程池 (Raster)、GPU进程主线程 (GPU) 等。每个线程中可以看到不同类型的任务,如脚本 (Scripting)、渲染 (Rendering)、绘制 (Painting)、系统 (System) 等。每个任务中可以看到不同层级的函数调用栈和耗时。
  • 性能摘要部分,显示了在检测性能的时间范围内,各个类型任务所占用的时间比例和总时长,如加载 (Loading)、脚本 (Scripting)、渲染 (Rendering)、绘制 (Painting)、其他 (Other)、空闲 (Idle) 等。
  • 性能细节部分,显示了在检测性能的时间范围内,一些关键的时间节点在何时产生的数据信息,如首次内容绘制 (FCP)、最大内容绘制 (LCP)、首次有意义绘制 (FMP)、DOM内容加载事件 (DCL)、页面加载事件 (L) 等。
  • 底部信息栏部分,显示了当前选中的任务或函数的详细信息,如名称、耗时、文件位置等。

为什么使用 Performance

  1. GC 的目的是为了实现内存空间的良性循环;
  2. 良性循环的基石是合理使用;
  3. 时刻关注才能确定是否合理;
  4. Performance 提供多种监控方式,可以时刻监控内存。

使用步骤

1)打开浏览器输入目标地址 – Chrome为例;

image.png

2)进入开发人员工具面板,选择性能;

image.png

3)开启录制功能,访问具体界面;

image.png

4)执行用户行为,一段时间后停止录制;

5)分析界面中记录的内存信息

image.png

Lighthouse

Lighthouse  是一个开源工具,可以对网页进行自动化的性能和质量审查。它可以生成详细的性能报告,指导您进行优化。

image.png

Lighthouse 架构从5个方面来分析页面:性能辅助功能最佳实践搜索引擎优化和 PWA。像性能方面,会给出一些常见的耗时统计。除此以外,还会给到一些详细的优化方向。

总结

以上内容就是优化JavaScript代码并提高应用程序的性能的一些内容。要注意的是,优化是一个持续的过程,需要不断地检查和改进代码。

通过合理的代码结构、避免不必要的操作和利用现代浏览器的优化特性,我们可以最大程度地提升应用程序的性能和用户体验。