前端性能优化
性能优化的目的是为了实现资源的快速加载和响应。性能优化前,需要先分析性能,目的是分析出包含页面渲染、网络传输和文件加载等时间指标,对该页面进行评估分析。找出影响性能的主要因素和瓶颈,对此给出性能优化解决方案。
1. 性能分析
1.1. Chrome 浏览器的 Performance
Chrome 浏览器的 Performance 选项卡主要用于对页面进行性能分析,以下是使用步骤:
- 开发者工具中,找到 “Performance” 标签。
- 在 Performance 选项卡下,点击录制,或重新加载可以录制整个网页加载过程。可以开启CPU 6倍降速,降低 6 倍性能。通过重新加载
https://developer.mozilla.org/
页面可以看到具体的性能指标
从以上摘要可以看出:HTML(蓝色)、脚本(脚本)、样式表(紫色)、媒体文件(绿色)、其他资源(灰色/黑色)都标出了耗时。
CPU 也按照时间线标出了HTML(蓝色)、脚本(脚本)、样式表(紫色)、媒体文件(绿色)、其他资源(灰色/黑色)的占用的空间。
网络也按照时间长短标出了具体是哪一个 js 占用更长等等。
但是这些信息还看不出具体的性能问题,需要进一步确认:
点击主要(main)中具体的任务(task),摘要下会显示警告,例如:
提示:已强制自动重排,可能是性能瓶颈,点击进入可以参看具体的代码,找到并解决/优化。
1.2. performance.timing
通过 performance.timing
,可以获取到一系列的性能指标,如页面白屏耗时、完全加载耗时、解析DOM树耗时等。这些指标对于分析和优化网页性能至关重要。通过对这些指标的分析,可以找出性能瓶颈,从而针对性地进行优化,提升用户体验。
例如:
列出了多个时间节点的具体时间戳,通过 responseEnd - responseStart
能够得到响应时间。
1.3. lighthouse
lighthouse 是 Google 开发和开源的 Web 性能测试的工具。能够对网页进行自动化的性能分析,收集现代性能指标,并提供关于开发者最佳实践的建议。
- 在 Chrome 浏览器开发者工具中找到 Lighthouse 选项
- 选择你想要进行性能测试的方向(例如桌面或移动)。
- 点击“Generate Report”生成报告。
例如还是访问 https://developer.mozilla.org/
生成报告如下:
列出了性能(Performance)、可访问性(Accessibility)、最佳实践(Best Practices)、SEO、渐进式Web应用(PWA) 5 项指标分别的评分。
同时,底部还列出了诊断,提供解决方案:
2. 性能优化
2.1. 图片优化
前端开发中,图片占到了很大比重。
- 减少图片
去掉毫无意义的装饰类的图片。比如可以用 icon 来替代一些小图标。
- 通过 CSS 模拟图形
如果是纯图形,可以通过 CSS 代码生成。
- 使用合适的图片格式
图片颜色较少、需要阴影,可以使用 png。相同质量下,WebP 格式比 JPEG 图像少 40% 左右。
2.2. 图片懒加载
让图片元素进入视口范围内才被加载。
2.3. DOM 优化
- 减少重排和重绘
将结果缓存,避免重复计算。引入 DocumentFragument 文档片段,对 DOM 的操作先在该片段下再才做完成了在放置在 DOM 节点内。使用 classList 合并属性
- 节流和防抖
2.4. WebWorker 介入数据密集型操作
Web Worker 为 JS 创建了多线程环境。可以将一些运算分配到子线程运算,减轻主线程压力,使得主线程和子线程之间互不干扰。
下面以后台数值计算为例演示:
// main.js
let worker = new Worker("./worker.js");
worker.postMessage({
status: 0
});
worker.onmessage = function (event) {
document.querySelector(".calc").innerHTML = event.data;
worker.terminate(); // 主线程关闭
};
// worker.js
onmessage = function (event) {
console.log(event);
let status = event.data.status;
if (status === 0) {
startToCalc();
}
}
function startToCalc() {
let arr = [];
for (let i = 1; i <= 1000; i++) {
arr.push(i);
}
let tStart = new Date().getTime();
let total = arr.reduce((sum, item) => sum + item);
let tEnd = new Date().getTime();
console.log(`耗时:, ${tEnd - tStart}, ms`);
postMessage(`处理完成,耗时: ${tEnd - tStart} ms,和为:${total}`); // 使用中文可能会引起乱码
self.close(); // 子线程关闭
}
2.5. Webpack 优化
- 减少文件匹配范围
在 rules 中配置 exclude,减少 loader 的搜索范围。
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_module/, // 指定排除掉的目录
include: path_resolve(__dirname, 'src') // 指定要处理的目录
}
]
}
- 缓存 babel-loader 结果
将转义后的结果缓存到文件系统中,配置 cacheDirectory 选项:
rules: [
{
test: /\.js$/,
use: 'babel-loader?cacheDirectory',
exclude: /node_module/
}
]
- 优化模块配置
使用短路径 alias。
resolve: {
alias: {
"@components": path,resolve(__dirname, 'src/components')
}
}
为了使用 src/components
下的组件,直接 import { x } from "@components";
。
- 配置 parser
配置不希望被转换的文件:
rules: [
{
parser: {
System: false // systemjs 不被解析
}
}
]
- 从 bundle 中摘除第三方库
增加 external 配置,可以摘除第三方库:
external: [
/axios/, /lodash/
]
axios 和 lodash 可以通过 CDN 引入,提高加载速度。
- 使用 url-loader 优化图片
url-loader 可以将较小的静态文件内联到静态文件中:
rules: [
{
test: /.(jpg|png|jpeg|gif)$/,
loader: 'url-loader',
options: {
limit: 10 * 1024, // 把小于 10KB 的图片内联到文件中
}
}
]
如果不配置, 则将获取一个文件,并放在 bundle 文件同级目录中。
性能优化是循循渐进的过程,不像 bug 那样一次性解决。