前端性能优化主要是为了提高页面的加载速度,优化用户的访问体验。我认为可以从这些方面来进行优化。 第一个方面是页面的内容方面 (1)通过文件合并、css 雪碧图、使用 base64 等方式来减少 HTTP 请求数,避免过多的请求造成等待的情况。
(2)通过 DNS 缓存等机制来减少 DNS 的查询次数。
(3)通过设置缓存策略,对常用不变的资源进行缓存。
(4)使用延迟加载的方式,来减少页面首屏加载时需要请求的资源。延迟加载的资源当用户需要访问时,再去请求加载。
(5)通过用户行为,对某些资源使用预加载的方式,来提高用户需要访问资源时的响应速度。
第二个方面是服务器方面 (1)使用 CDN 服务,来提高用户对于资源请求时的响应速度。
(2)服务器端启用 Gzip、Deflate 等方式对于传输的资源进行压缩,减小文件的体积。
(3)尽可能减小 cookie 的大小,并且通过将静态资源分配到其他域名下,来避免对静态资源请求时携带不必要的 cookie
第三个方面是 CSS 和 JavaScript 方面 (1)把样式表放在页面的 head 标签中,减少页面的首次渲染的时间。
(2)避免使用 @import 标签。
(3)尽量把 js 脚本放在页面底部或者使用 defer 或 async 属性,避免脚本的加载和执行阻塞页面的渲染。
(4)通过对 JavaScript 和 CSS 的文件进行压缩,来减小文件的体积。
加载阶段
首页加载图片过多的问题,可以通过以下几种方法解决:
- 通过懒加载的方式处理非首屏的图片
- 对于小图标可以采用 iconfont 的方式解决
- 对于小图片可以采用雪碧图的方式解决
首页的请求量过多,可以通过一些手段来减少资源的请求量,比如:
- 通过 nginx 服务器来做资源文件的合并或者通过 Webpack 等打包工具进行物理打包
- 在代码层面,对于需要引入一些大型第三方库的时候,可以通过特定的 Babel 插件来进行按需加载
- 还有可以使用前端路由懒加载,从而可以减少首页的 JS 和 CSS 的大小
优化图片的做法
熊猫站:智能压缩 PNG 和 JPG 的一个网站
图片的优化,也是从两个方面来考虑:太多 和 太大。
- 可以通过懒加载减少图片的请求,或者通过雪碧图来合并图片,以及将小图转化成 base64 的格式,来解决多的问题。
- 图片大的问题,可以通过自动化压缩工具来压缩图片,如熊猫站。或者使用 WebP 格式的图片。
Webpack 打包优化,也是从两个方面来考虑:太多 和 太大。
- 可以通过设置 mode = production 来默认实现 Webpack 对代码的混淆和压缩,从而最大程度的减少代码体积
- 使用 Webpack + dynamic import 并结合路由的入口文件做拆包处理。
- 并且可以设定一些打包策略,并配合网络缓存做最终的加载性能优化。
实现 CDN 加速
CDN 服务器主要是用来放静态资源的服务器,可以用来加速静态资源的下载 CDN 之所以能够加速,是因为会在很多地方都部署 CDN 服务器,如果用户需要下载静态资源,会自动选择最近的节点下载 同时由于 CDN 服务器的地址一般都跟主服务器的地址不同,所以可以破除浏览器对同一个域名发送请求的限制
运行阶段
渲染十万条数据如何不造成卡顿
- 无论是浏览器中的 DOM 和 BOM,还是 NodeJS,它们都是基于 JavaScript 引擎之上开发出来的
- DOM 和 BOM 的处理最终都是要被转换成 JavaScript 引擎能够处理的数据
- 这个转换的过程很耗时
- 所以在浏览器中最消耗性能的就是操作 DOM
优化渲染很多数据的情况:尽可能的减少 DOM 的操作
eg:假如有一个需求,我们要在一个页面中 ul 标签里渲染 十万 个 li 标签。
// 插入十万条数据
const total = 100000;
let ul = document.querySelector('ul'); // 拿到 ul
// 懒加载的思路 -- 分段渲染
// 1. 一次渲染一屏的量
const once = 20;
// 2. 全部渲染完需要多少次,循环的时候要用
const loopCount = total / once;
// 3. 已经渲染了多少次
let countHasRender = 0;
function add() {
// 创建虚拟节点,(使用 createDocumentFragment 不会触发渲染)
const fragment = document.createDocumentFragment();
// 循环 20 次
for (let i = 0; i < once; i++) {
const li = document.createElement('li');
li.innerText = Math.floor(Math.random() * total);
fragment.appendChild(li);
}
// 最后把虚拟节点 append 到 ul 上
ul.appendChild(fragment);
// 4. 已渲染的次数 + 1
countHasRender += 1;
loop();
}
// 最重要的部分来了
function loop() {
// 5. 如果还没渲染完,那么就使用 requestAnimationFrame 来继续渲染
if (countHasRender < loopCount) {
// requestAnimationFrame 叫做逐帧渲染
// 类似于 setTimeout(add, 16);
// 帧:一秒钟播放多少张图片,一秒钟播放的图片越多,动画就约流畅
// 1000/60 = 16
window.requestAnimationFrame(add);
}
}
loop();// 插入十万条数据
const total = 100000;
let ul = document.querySelector('ul'); // 拿到 ul
// 懒加载的思路 -- 分段渲染
// 1. 一次渲染一屏的量
const once = 20;
// 2. 全部渲染完需要多少次,循环的时候要用
const loopCount = total / once;
// 3. 已经渲染了多少次
let countHasRender = 0;
function add() {
// 创建虚拟节点,(使用 createDocumentFragment 不会触发渲染)
const fragment = document.createDocumentFragment();
// 循环 20 次
for (let i = 0; i < once; i++) {
const li = document.createElement('li');
li.innerText = Math.floor(Math.random() * total);
fragment.appendChild(li);
}
// 最后把虚拟节点 append 到 ul 上
ul.appendChild(fragment);
// 4. 已渲染的次数 + 1
countHasRender += 1;
loop();
}
// 最重要的部分来了
function loop() {
// 5. 如果还没渲染完,那么就使用 requestAnimationFrame 来继续渲染
if (countHasRender < loopCount) {
// requestAnimationFrame 叫做逐帧渲染
// 类似于 setTimeout(add, 16);
// 帧:一秒钟播放多少张图片,一秒钟播放的图片越多,动画就约流畅
// 1000/60 = 16
window.requestAnimationFrame(add);
}
}
loop();结论:
- 可以使用 document.createDocumentFragment 创建虚拟节点,从而避免引起没有必要的渲染
- 当所有的 li 都创建完毕后,一次性把虚拟节点里的 li 标签全部渲染出来
- 可以采取分段渲染的方式,比如一次只渲染一屏的数据
- 最后使用 window.requestAnimationFrame 来逐帧渲染
导致浏览器卡顿的原因一般都是操作 DOM 的次数太频繁。 如果想要渲染很多条数据不造成卡顿,那么就一定要尽可能的减少操作 DOM 的次数。 比方说 React 的虚拟 DOM,本质上就是用 JS 数据来模拟真实 DOM 树,从而大大减少了操作真是 DOM 的次数。 还有在渲染的时候,可以使用 document.createDocumentFragment 创建虚拟节点,从而避免引起没有必要的渲染 也可以采取分段渲染的方式,最后使用 window.requestAnimationFrame 来逐帧渲染
渲染优化
- 禁止使用
iframe(阻塞父文档onload事件) - 使用
CSS3代码代替JS动画(尽可能避免重绘重排以及回流) - 对于一些小图标,可以使用 base64 位编码,以减少网络请求。但不建议大图使用,比较耗费
CPU - 小图标优势在于
- 减少
HTTP请求 - 避免文件跨域
- 修改及时生效
- 减少
- 用
innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能 - 当需要设置的样式很多时设置
className而不是直接操作style - 图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳
性能优化总结
在前端中性能优化的点主要分为两个阶段:
- 初始阶段,主要就是加载方面优化的问题。所有问题的指导原则就两点:
- 尽可能的减少前端资源的数量
- 尽可能的减小前端资源的大小
- 运行阶段,主要就是渲染方面优化的问题。只要是在浏览器中,所有的问题的指导原则就是:
- 尽可能的减少操作 DOM

