送你【14种前端性能优化方式】助你网站性能刚刚的
前端性能优化这个问题,每个项目都会接触到而且面试中也会经常问到你项目中是怎么做性能优化的,接下来为大家介绍一下我在项目中做性能优化的几种方式。
1. css、js资源位置
这个点是优化加载。
css 放 header,js 放footer。
目前工程化实践:不用管,webpack 构建自动安排好了。
备注:
1、移动端用于计算 rem 的js文件需要放于header头部,在css之前,避免页面二次布局。
2、css 会阻塞 html 的渲染和 js 的执行,js 会阻塞 html 的解析和渲染,因此 css 是有可能阻塞 html 的解析和渲染的。
2. 资源混淆压缩
这个点是减少资源大小,标重点,该手段优化效果明显。
混淆压缩资源,一方面是降低代码可读性达到一定的安全作用,一方面是减少资源的大小。
目前工程化实践:不用管,webpack 构建自动安排好了。(手写配置的自己记得配上混淆)
3. 资源加上 gzip
这个点是减少资源大小,标重点,该手段优化明显,一般能将资源缩小 50% 以上。
需要服务端进行配置,cdn 默认都有该配置,如果资源没上 cdn,则自己在应用服务器上的 nginx 加上 gzip。
目前实践:很多项目为了在线构建或图方便,静态资源都放在应用服务器上,因此这个点也是很多应用没有优化的点。
4. 资源合并
这个点是减少请求数量。
浏览器中对同个域名最多并行6个请求,超出的则进入请求队列等待。减少请求数量可以减少 tcp 握手次数,以及减少网络抖动带来的影响。
目前工程化实践:webpack 默认对 node_modules 中的第三包进行合并打包,合成一个 chunk 文件,因此这块不用管。
这里涉及到一个策略问题,后面将其他相关的优化手段说明完后进行描述。
5. 图片做雪碧图/iconfont/base64
这个点也是减少请求数量,标重点,有时候该手段能达到很好的优化效果(当一个项目中切图很多的时候)。
这里的图片是项目中用到的切图,雪碧图现在不用管了,基本不这么做了。
iconfont:只针对单色图标,多色图标只能用 svg(多个svg合成一个) 或者 图片做 base64
base64:图片直接做 base64,这个也是目前普遍使用的,一般对 4kb (有的是设置 10kb,根据自己项目情况衡量)以下的图片做 base64。
目前工程化实践:webpack 的 url-loader 做了该功能,配上即可(vue 脚手架都自带着)。
6. http 缓存
这个点是在首次访问后二次复用本地资源,减少请求。
http 缓存只建议加在 cdn 上,应用服务器上不要加缓存,带 hash 的可以加。
对于打包出来的 hash chunk 资源包,缓存时间可以设置得长一些,比如 30 天、90 天之类的。
其他非 hash chunk 的资源包,本质上都可能存在改内容不改地址的情况,因此缓存禁止设置过长,一般为 1 小时,这样 cdn 更新时,用户的浏览器在 1 小时后也能得到更新。
备注:
1、cdn 缓存非 2 类,一类为节点服务器的缓存,一类为用户浏览器的本地缓存,平时 np 上只是刷新节点服务器的缓存,做不到刷新用户浏览器的缓存。
2、移动端 app 上的 http 缓存只在当前这次 app 存活期间遵循 http 缓存策略,当你的 app 杀死退出后,缓存就会失效。
7. 压缩图片/使用合适的图片大小
这个点是减少资源大小,标重点,优化效果明显,很多项目都是图片达到几百 kb 甚至 1M 以上。
1)切图图片压缩后再使用,一般用切图的 2 倍图即可,使用 tinypng.com 进行压缩,压缩一遍就好。
2)线上图片。
8. 图片懒加载
这个点是减少首屏访问的请求数量,标重点,对图片多的页面效果明显,移动端上一屏展示的内容比较少,对列表页的优化效果也明显。
直接用 vue-lazyload 组件就好了。
备注:
图片懒加载和路由懒加载不是一个东西,区分好,不过本质上都是减少首屏加载的资源请求。
9. 资源放 CDN
资源放 cdn 原本目的是为了让用户请求更快打到服务器上(节点服务器离用户比较近),但现在网速很快,网络节点上的延迟没有以前那么明显,因此该优化手段不是很明显。
放 CDN 另一个目的是上缓存,不过应用服务器衡量好利弊也可以加缓存。
商品管理、学习中心等移动端应用静态资源没有放 CDN 上,也做到了整页加载时间 TP90 在 2 秒内。
10. 避免重绘重排/减少dom结构复杂度
这个点是优化渲染,效果不明显。
目前浏览器内核很强大了,渲染上的耗时大部分情况下是比请求耗时小不少的。
11. 合理利用路由懒加载
这个点只针对前后端分离的前端应用,优化效果看情况,有时候可能形成反效果。
面试的过程中,基本每个面试者我都必问,但没有答得特别好的。
路由懒加载和 1.4 资源合并 有一定的冲突性。
1)资源合并一般针对不经常修改的第三方包,对于业务 JS 代码一般不做合并。
2)路由懒加载是将页面的JS代码拆分成一个一个的 chunk 包,只有加载页面的时候再去加载 JS 资源。
3)用户经常访问的页面,不要用路由懒加载,经常访问的页面主要是首页;对于用户经常访问的页面,因为用户肯定需要将页面的 chunk js 加载下来才可以访问页面,路由懒加载会导致先加载 资源清单 manifest 文件,再去加载页面的 chunk 包,这样就形成了一个资源的串行请求,本来可以一次加载下来却非得拆分成2次而且还是串行的不是并行的。
一个页面的 chunk 包其实不会很大,将它合进主 chunk 里也不会带来明显的请求耗时加大,反而请求次数多了带来的网络延迟消耗比较明显。
12. 组件库按需加载
这个点是针对前后端分离的前端应用,优化方向是减少资源大小,标重点,优化效果明显。
一个完整的组件库多大40+个组件,整个包的大小加上 gzip 至少也是 100kb 以上(element-ui 300kb+),但我们项目中常用的组件也就十几二十个,不需要用到那么多组件。
备注:
除了为了让多个系统最高效地复用静态资源缓存,会考虑对第三方包用 CDN 而非 npm 安装,具体情况得多系统衡量,单个系统的优化不明显。
13. 延迟加载第三方包
这个点是减少首屏加载的资源,但整体页面需要加载的资源没有减少,只是做了分段处理,标重点,优化效果明显。
屏幕能展示的东西就这么多,对于不在屏幕中的内容,且依赖第三方 CDN 包的功能,又或者用户手动触发某个功能依赖第三方 CDN 包(一般页面渲染过程中不需要使用),可以延迟加载这个 CDN 包,没必要在 html 中直接引入,用动态 script 插入使用。
这样可以减少首屏加载渲染的压力。
备注:
要用到的时候才去加载第三方包,就存在第三方包加载过长导致用户觉得卡顿的情况,这是它的劣势,这个问题下面这个优化点解决。
14. 对资源做 preload 和 prefetch
这个点是对要用到的资源提前加载好,等要请求的时候直接使用加载好的资源去执行,优化效果看情况。
preload 提前加载当前页面需要用到的资源(不执行),prefetch 提前加载下个页面要用到的资源(不执行)。
这个优化点对优化首屏加载效果看情况,对后续的操作体验比较好。
结合 2.3 延迟加载第三方包 的手段,为了提升用户的交互体验,我们将被我们延迟加载的第三方包使用 preload 进行预加载,这样用户交互的时候,直接执行已经提前加载好的资源即可。
同时对于前后端分离的项目,使用了路由懒加载,这时候加上 prefetch 提前加载下一个页面的资源,可以让用户无感切换页面,不会出现页面延迟出现的情况。
目前工程化实践:vue 脚手架(3.0开始)默认都带着这个功能,自己配的 webpack 配置加上 @vue/preload-webpack-plugin 插件。
手动写法:
<link href=/js/6.719bfbca.js rel=prefetch> <link href=/css/app.5abb7818.css rel=preload as=style> <link href=/js/app.d22ec8fc.js rel=preload as=script> 复制代码
2.5 使用多个图片系统域名
这个点是扩大并发请求,优化效果看情况,对于首页这种商品图很多的页面,效果明显。
前面提到一个域名同时并发 6 个请求,但页面的图片可能不止 6 张,为了让图片更快得呈现,使用多个图片系统域名扩大图片的加载请求数量。
凡是图片系统域名都很多,如 img10.xx.com , img11.xx.com, img20.xx.com, img30.xx.com
等等。
2.6 对域名做 dns 预解析
这个点是减少连接时长,效果在 pc 上一般,在移动上有一定效果,因为移动端的 dns 解析比较差。
前面提到用多个图片系统域名,就带来了多次 dns 解析,有时候页面的加载耗时会在 dns 解析上面卡很久;此外一个页面中至少会请求一个后端接口域名(多的情况2,3个),因此加上一层 dns 预解析是比较好的。
示例:
<link rel="dns-prefetch" href="//img10.xx.com"> 复制代码
将会用到的域名直接加到 html 的 header 中即可,不需要通过 webpack 去生成。
2.7 升级 webpack 版本
这个点本质上也是减少资源大小。
webpack1、webpack2 打包出来的资源包明显大于 webpack3、webpack4。
webpack 的打包机制在优化,用着 webpack1、webpack2 的老项目做 webpack 升级后可以明显减少包的大小。
2.8 小包替大包,手写替小包
这个点本质上也是减少资源大小,优化效果看用到的包的情况。
有些第三方包功能很强大很齐全,但我们只是用到里面的一个小功能而已,将这么大而全的包引入项目中有点得不偿失,可以选择找能实现同样功能的小包或者手撕进行替换。
如 dayjs 替换 momentjs ,momentjs 不做 gzip 的话也接近 100 kb 了。
比如页面用到了 Promise,没必要将整个 babel-polyfill 打进去,装个 es6-promise 就好了。
三、总结
性能优化手段总结下来可以分为以下几个方向:
3.1、减少首屏资源大小
1.2 资源混淆压缩、1.3 资源加上 gzip、1.7 压缩图片/使用合适的图片大小、1.8 图片懒加载、2.1 合理利用路由懒加载、2.2 组件库按需加载、2.3 延迟加载第三方包、2.7 升级webpack 版本、2.8 小包替打包,手写替小包
3.2 减少网络消耗/合理利用网络请求
1.4 资源合并、1.5 图片做雪碧图/iconfont/base64、1.6 http 缓存、1.9 资源放CDN、2.4 对资源做 preload 和 prefetch、2.5 使用多个图片系统域名、2.6 对域名做 dns 预解析
3.3 优化渲染
1.1 css、js 资源位置、1.10 避免重绘重排/减少 dom 结构复杂度
对于首次访问页面来说,3.1 减少首屏资源大小优化效果最明显。
结语
要想页面加载最快,其实就是回归本质,页面简单,没多少资源,不上框架,直接用原生,能用 css 实现的就不要用 js,一个页面中就只有一个 js 文件和 css 文件,这样的页面肯定能达到秒开,但现实情况就是现在的前端应用发展得越来越复杂,只有一些 app 的小页面能做到这么简单,不上框架了。
备注:
天猫那些双十一的技术文章,那么多图片的活动页能实现秒开,主要还是依托于客户端的支持,要么用跨端技术做热更新下发,要么客户端提前加载缓存好活动页面,要用的时候切换过去。
点赞支持、手留余香、与有荣焉,动动你发财的小手哟,感谢各位大佬能留下您的足迹。
作者:_Battle
链接:https://juejin.cn/post/7018376594720817182