性能优化与调试技巧
本文探讨如何通过优化JavaScript代码来提高性能,包括减少重绘和重排、使用节流和防抖技术、使用性能分析工具等;
常见的JavaScript性能问题
在进行JavaScript性能优化之前,我们需要了解一些常见的JavaScript性能问题。以下是一些常见的问题:
1.频繁的DOM访问:频繁地访问DOM元素可能会导致性能问题。因为访问DOM元素是非常昂贵的操作,它需要从浏览器中获取元素的引用并计算元素的位置和大小。
2.过多的HTTP请求:过多的HTTP请求会导致页面加载时间过长,从而影响用户体验。每次发送HTTP请求都需要建立TCP连接和传输数据,这些操作需要时间和资源。
3.大量的JavaScript文件:如果Web应用程序使用大量的JavaScript文件,那么加载时间会变得很长,从而影响用户体验。每个JavaScript文件都需要建立一个HTTP请求,并且需要解析和执行,这些操作都需要时间和资源。
4.内存泄漏:内存泄漏是指在代码中创建的对象无法被垃圾回收器正确地回收。如果JavaScript代码中存在内存泄漏,那么在长时间运行Web应用程序时,内存使用率可能会不断增加,从而导致性能问题。
减少重绘和重排
引起重排重绘的原因有:
- 添加或者删除可见的DOM元素,
- 元素尺寸位置的改变
- 浏览器页面初始化,
- 浏览器窗口大小发生改变,重排一定导致重绘,重绘不一定导致重排,
减少重绘重排的方法有:
- 在用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';
- 使用display:none让父盒子先消失,然后再对此盒子添加一些子元素,然后再将这个父盒子display:block显示出来。浏览器一共发生了两次重排,即第一次的隐藏和最后面的显示。中间的操作都不会造成重排。
- 使用文档片段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>
节流和防抖
节流和防抖严格意义上来说是属于性能优化领域的,实际上遇到的频率很高,如果不做防抖或者节流可能会出现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
- GC 的目的是为了实现内存空间的良性循环;
- 良性循环的基石是合理使用;
- 时刻关注才能确定是否合理;
- Performance 提供多种监控方式,可以时刻监控内存。
使用步骤
1)打开浏览器输入目标地址 – Chrome为例;
2)进入开发人员工具面板,选择性能;
3)开启录制功能,访问具体界面;
4)执行用户行为,一段时间后停止录制;
5)分析界面中记录的内存信息
Lighthouse
Lighthouse 是一个开源工具,可以对网页进行自动化的性能和质量审查。它可以生成详细的性能报告,指导您进行优化。
Lighthouse 架构从5个方面来分析页面:性能、辅助功能、最佳实践、搜索引擎优化和 PWA。像性能方面,会给出一些常见的耗时统计。除此以外,还会给到一些详细的优化方向。
总结
以上内容就是优化JavaScript代码并提高应用程序的性能的一些内容。要注意的是,优化是一个持续的过程,需要不断地检查和改进代码。
通过合理的代码结构、避免不必要的操作和利用现代浏览器的优化特性,我们可以最大程度地提升应用程序的性能和用户体验。