前端性能优化,一直以来都是一个老生常谈的问题。页面响应的时间快慢等性能问题,直接决定了用户体验的好坏,从而决定了用户消费的欲望。所以,前端优化势在必行。那么,我们就来判断一下,可以做的前端性能优化有哪些?
1、loading
对,你说的没错,这中优化方式确实是很low,但是请问,你在开发中加loading了吗?没加,请加上。就这这么简单,别问怎么做。
2、骨架屏
这个听起来似乎要高大上一点,应该至少要比loading要高大上。
实现骨架屏的方式:
(1)base64图片:辛苦设计小姐姐,设计一张base64图片,然后初始化的时候,显示base64图片,等待接口响应数据返回后,将base64图片隐藏,其原理和loading一样。有个不好的地方时,无论你的页面是什么结构,显示的骨架都一样,这样也不太好不是。
(2)webpack: vue-skeleton-webpack-plugin是配置,这水解决骨架屏的完美方案。它将插入骨架屏的方式由手动改为自动,原理在构建时使用 Vue 预渲染功能,将骨架屏组件的渲染结果 HTML 片段插入 HTML 页面模版的挂载点中,将样式内联到 head 标签中。这个插件可以给单页面的不同路由设置不同的骨架屏,也可以给多页面设置,同时为了开发时调试方便,会将骨架屏作为路由写入 router 中,可谓是相当体贴了。
3、webp
webp 是一种新的图片格式,它的体积只有只有 JPEG 的2/3,将图片资源大量换成 webp 格式可以加快请求的速度。图片资源大部分都放在阿里的 OSS 上,并且阿里提供了接口,可以在线将 png/jpeg 转为 webp 格式。
注意:webp 格式在浏览器兼容上还有一定的问题,所以需要判断浏览器是否支持 webp 格式哦。
以上三种属于正常简单的优化,下面我们就来讲讲比较高大上的优化:
1、网络优化
(1)service worker
ServiceWorker
是运行在浏览器后台进程里的一段 JS,它可以做许多事情,比如拦截客户端的请求、向客户端发送消息、向服务器发起请求等等,其中最重要的作用之一就是离线资源缓存。ServiceWorker
拥有对缓存流程丰富灵活的控制能力,当页面请求到 ServiceWorker
时,ServiceWorker
同时请求缓存和网络,把缓存的内容直接给用户,而后覆盖缓存。
注意:需要HTTPS才可以使用 ServiceWorker。
(2)http缓存
http缓存一般分为俩中:强缓存(本地缓存)和协商缓存(304缓存),普通刷新会启用 协商缓存,忽略 强缓存。只有在地址栏或收藏夹输入网址、通过链接引用资源等情况下,浏览器才会启用 强缓存。
强缓存:本地缓存是最快速的一种缓存方式,只要资源还在缓存有效期内,浏览器就会直接在本地读取,不会请求服务端。
协商缓存:协商缓存,顾名思义是经过浏览器与服务器之间协商过之后,在决定是否读取本地缓存,如果服务器通知浏览器可以读取本地缓存,会返回304状态码,并且协商过程很简单,只会发送头信息,不会发送响应体。
缓存的位置:
缓存位置一般分为:Memory Cache(内存缓存)和 Disk Cache(硬盘缓存)
内存缓存:读取快、持续时间短、容量小
硬盘缓存:读取慢、持续时间长、容量大
缓存优先级:Service Worker -> Memory Cache -> Disk Cache -> Push Cache
(3)http2
HTTP2 四个新特性:
-
多路复用,无需多个TCP连接,因为其允许在单一的HTTP2连接上发起多重请求,因此可以不用依赖建立多个TCP连接。
-
二进制分帧,将所有要传输的消息采用二进制编码,并且会将信息分割为更小的消息块。
-
头部压缩,用HPACK技术压缩头部,减小报文大小
-
服务端推送,服务端可以在客户端发起请求前发送数据,换句话说,服务端可以对客户端的一个请求发送多个相应,并且资源可以正常缓存。
注意:使用 http2 的前提是必须是 https。
(3)资源预加载
简单说,提前加载资源,当用户需要查看时可直接从本地缓存中渲染。
总结:对当前页面需要的资源,使用 preload 进行预加载,对其它页面需要的资源进行 prefetch 预加载。
preload
preload
页面加载的过程中,在浏览器开始主体渲染之前加载。
<!-- 对sty1e.cs5和 index.js进行pre1oad预加载 -->
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="index.js" as="script">
prefetch
prefetch
页面加载完成后,利用空闲时间提前加载。
<!--对资源进行 prefetch预加载-->
<link rel="prefetch" href="next.css">
<link rel="prefetch" href="next.js">
注意:vue-cli
默认开启 prefetch
,可在 vue.config.js
中全局禁用 prefetch
,再针对指定模块开启。
dns-prefetch
页面加载完成后,利用空闲时间提前加载。
<link rel="dns-prefetch" href="//example.com">
(4)异步无阻塞加载js
defer
<script src="d.js" defer></script>
<script src="e.js" defer></script>
-
不阻止解析 document, 并行下载 d.js, e.js
-
即使下载完 d.js, e.js 仍继续解析 document
-
按照页面中出现的顺序,在其他同步脚本执行后,DOMContentLoaded 事件前 依次执行 d.js, e.js。
async
<script src="b.js" async></script>
<script src="c.js" async></script>
-
不阻止解析 document, 并行下载 b.js, c.js
-
当脚本下载完后立即执行。(两者执行顺序不确定,执行阶段不确定,可能在 DOMContentLoaded 事件前或者后 )
2、构建优化
(1)gzip 压缩:compression-webpack-plugin
gzip
压缩效率非常高,通常可以达到 70% 的压缩率,也就是说,如果你的网页有 30K,压缩之后就变成了 9K 左右。
//npm i -D compression-webpack-plugin
configureWebpack: config => {
const CompressionPlugin = require('compression-webpack-plugin')
config.plugins.push(new CompressionPlugin())
}
(2)去除console:terser-webpack-plugin
线上项目自然不应该被看到控制台的打印日志,所以我们需要将 console.log
都去除掉。
//npm i -D terser-webpack-plugin
configureWebpack: config => {
const TerserPlugin = require('terser-webpack-plugin')
config.optimization.minimizer.push(
new TerserPlugin({
extractComments: false,
terserOptions: { compress: { drop_console: true } },
})
)
}
(3)去除 SourceMap:
由于打包后的文件经过了压缩、合并、混淆、babel编译后的代码不利于定位分析bug。
module.exports = {
productionSourceMap: false,
}
(4)预渲染:prerender-spa-plugin
简单说,就是将浏览器解析 javascript
动态渲染页面的这部分工作,在打包阶段就完成了,(只构建了静态数据)换个说法在构建过程中,webpack
通过使用 prerender-spa-plugin
插件生成静态结构的 html
。
// npm i -D prerender-spa-plugin
configureWebpack: config => {
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
config.plugins.push(
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: ['/'],
minify: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
keepClosingSlash: true,
decodeEntities: true,
sortAttributes: true,
},
renderer: new PrerenderSPAPlugin.PuppeteerRenderer({
renderAfterDocumentEvent: 'render-event',
renderAfterTime: 5000,
// headless: false,
}),
})
)
}
注意:路由模式必须为 history
,如果不设置 history
模式,也能运行和生成文件,每个 index.html
文件的内容都会是一样的。
(5)服务端渲染:vue-ssr-render
为了解决seo和首屏渲染的问题,为们还可以使用服务端渲染的方式。
//webpack.client.js
............
const VueSSRClientPluguin = require('vue-server-renderer/client-plugin');
..............
plugins:[
new VueSSRClientPluguin()
]
//webpack.server.js
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');
...............
entry:{
main:'./entry-server.js'
},
output:{
filename:'server-bundle.js',
libraryTarget:'commonjs2'
},
............
plugins:[
new VueSSRServerPlugin ()
]
当然还有很多其他的优化手段,,,未完待续。。。。