事实上, 只有
10%-20%
的最终用户响应时间是发在从Web服务器获取HTML文档并传送到浏览器中的。若是但愿可以有效地减小页面的响应时间,就必须关注剩余80%-90%
的最终用户体验。 --Steve Soudersjavascript
在这篇博客中,我根据工做中的实际项目经验和一些测试的经验中总结出了前端页面在性能上优化方案。其中一些经验吸取自《高性能网站建设指南》Steve Souders 著 电子工业出版社。css
遵循HTML规范
,将样式表放在头部,能够有效避免白屏
和无样式内容的闪烁
。<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 使用link标签将样式表放在文档的HEAD中 -->
<link rel="stylesheet" href="example.css">
</head>
<body></body>
</html>
复制代码
将脚本放在顶部会形成的影响: 脚本阻塞对其后面内容的显示
; 脚本会阻塞对其后面组件的下载
;html
将脚本放在底部</body>
标签以前, 相似于document.body.appendChild(yourScript), 不会阻塞页面内容的呈现,并且页面中的可视组件能够尽早下载。前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<link rel="stylesheet" href="example.css">
</head>
<body>
<!-- 将脚本放在底部 -->
<script src="example.js"></script>
</body>
</html>
复制代码
将
多个图片
合成一张图片
,经过background-position来定位所须要的图片。每次请求的话只须要请求一张图片
减小http请求。(若是使用图标的话建议使用svg,也可使用iconfont)vue
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4SUJRXhpZgAATU> 复制代码
多个小文件
中,会下降性能
,每一个文件都会致使一个额外的
HTTP请求Good
java
<link rel="stylesheet" href="example.css">
<script src="example.js"></script>
复制代码
bad
node
<style> // code </style>
<script> // code </script>
复制代码
能够配置缓存
有利于组件重用
CDN是构建在网络之上的内容分发网络,依靠部署在
各地的边缘服务器
,经过中心平台的负载均衡
、内容分发
、调度
等功能模块,使用户就近获取所需内容,下降网络拥塞,提升用户访问响应速度和命中率。CDN的关键技术主要有内容存储
和分发技术
。--摘自百度百科webpack
经过CDN引入的资源目前基本都是使用目前最新的HTTP2协议
,因此在性能上能够作到极致优化,感谢CDN。ios
gzip压缩能够节省
50%-70%
的网络开销
浏览器支持的压缩类型能够经过network的Accept-Encoding:
gzip
,deflate
来查看。支持deflate的浏览器也支持gzip,但不少浏览器支持gzip却不支持deflate
,所以gzip是最理想的压缩方法
webpack
项目能够看下面的Vue首屏加载时间优化
方案里的gzip压缩// npm install compression --save-dev
const compression = require('compression')
复制代码
前端打包压缩的有grunt,gulp,webpack,能够对HTML,CSS,Javascript代码压缩
本文中使用
nginx
服务器进行相关配置,使用apache
一样能够作到相关优化,具体操做请另Google
gzip
压缩gzip on; # 开启Gzip
gzip_static on; # 开启静态文件压缩
gzip_min_length 1k; # 不压缩临界值,大于1K的才压缩
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss; # 进行压缩的文件类型
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
复制代码
HTTP2在前端性能上主要表如今:请求和响应的多路复用、头部压缩
我的站点相关配置
nginx配置
location ~.*\.(svg|woff|js|css){
root /yourFilePath;
expires 1d;
}
复制代码
Expires
头来告诉Web客户端它可使用一个组件的当前副本,直到指定的时间为止 HTTP规范中简要地称该头为“在这一日期时间以后,响应将被认为是无效的”。它在HTTP响应中发送expires: Thu, 30 May 2019 20:51:42 GMT
复制代码
强缓存cache-control: max-age
server {
add_header Cache-Control max-age=72000;
}
复制代码
在解释缓存如何很好地改善传输性能以前,须要说起除了Expires 头以外的另外一种选择。HTTP 1.1引入了Cache-Control头来克服Expires头的限制
由于Expires头使用一个特定的时间,它要求服务器和客户端的时钟严格同步
。另外,过时日期须要常常检查,而且一旦将来这天到来了,还须要在服务器配置中提供个新的日期。
Cache-Control使用max-age指令指定组件被缓存多久, 若是从组件被请求开始过去的秒数少于max-age,浏览器就使用缓存的版本,这就避免了额外的HTTP请求。一个长久的max-age头能够将刷新窗设置为将来10年
。
Cache-Control: max-age=315360000
复制代码
Expires 和Cache-Control max-age.若是二者同时出现,HTTP规范规定max-age指令将重写Expires头
。
建议使用Cache-Control max-age
,若是使用expires你须要担忧它带来的时钟同步
和配置维护
问题。
Vue官方文档的Expires相关配置
浏览器必须产生这个HTTP请求,执行有效性检查, 但这仍
比简单地下载全部已过时的组件效率要高
(对比强缓存
)。若是浏览器缓存中的组件是有效的(即它可以和原始服务器上的组件相匹配),原始服务器不会返回整个内容,而是返回一个304 Not Modifed
状态码。
附:Vue首屏加载时间过长详细优化方案
首先附一张优化事后的图
首屏加载时间
从原来的10s
到2s
,测试的我的站点
注:我在优化vue项目的时候使用的是
vue@2.6.6
,vue-cli@3.4
。 若是是cli2的项目影响也不大,优化的方案是结合服务端和webpack的。
vue-cli脚手架默认配置已经大幅度优化了前端总体的性能,在此基础上,我又使用了三个优化项增长了大幅度提高
结合服务器相关优化第一条:开启gzip压缩
下面是前端项目中vue.config.js
中的配置
// 须要 npm install compression-webpack-plugin --save-dev
const CompressionWebpackPlugin = require('compression-webpack-plugin')
// 定义当前环境
const ENV = process.env.NODE_ENV || 'development'
module.exports = {
configureWebpack: config => {
// 若是是生产环境的话,开启压缩
if (ENV === 'production') {
// 参数配置文档: https://www.webpackjs.com/plugins/compression-webpack-plugin/
config.plugins.push(new CompressionWebpackPlugin({
algorithm: 'gzip',
test: /\.(js|css|html)$/,
threshold: 10240,
minRatio: 0.8
}))
}
}
}
复制代码
在
index.html
文件中经过环境来判断是否引入cdn文件,在vue.config.js
文件中webpack经过环境判断是否使用cdn引入文件的全局变量
webpack
和index.html
进行相关配置第一步 配置vue.config.js
,只须要在刚才配置Gzip压缩的基础上再加一段代码
:
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const ENV = process.env.NODE_ENV || 'development'
module.exports = {
configureWebpack: config => {
if (ENV === 'production') {
config.plugins.push(new CompressionWebpackPlugin({
algorithm: 'gzip',
test: /\.(js|css|html)$/,
threshold: 10240,
minRatio: 0.8
}))
// 配置externals就是当使用CDN进入的js文件在当前项目中能够引用
// 好比在开发环境引入的vue是import Vue from 'vue', 这个大写的Vue就是对应的下面的大写的Vue
config.externals = {
'vue': 'Vue',
'vue-router': 'VueRouter',
'axios': 'axios'
}
}
}
}
复制代码
第二步 配置index.html
,在body里使用EJS语法判断是否为生产环境
<body>
<div id="app"></div>
<% if (NODE_ENV === 'production') { %>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
<% } %>
</body>
复制代码
devtool | webpack中文网 你能够根据官网来对开发环境和生产环境进行详细配置
固然也能够像我同样直接productionSourceMap: false
干掉生产环境的sourceMap
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const ENV = process.env.NODE_ENV || 'development'
module.exports = {
configureWebpack: config => {
if (ENV === 'production') {
config.plugins.push(new CompressionWebpackPlugin({
algorithm: 'gzip',
test: /\.(js|css|html)$/,
threshold: 10240,
minRatio: 0.8
}))
config.externals = {
'vue': 'Vue',
'vue-router': 'VueRouter',
'axios': 'axios'
}
}
},
// 禁用生产环境的sourceMap
productionSourceMap: false
}
复制代码
请参考服务端优化第二条
更多更详细的优化方案详细能够参考雅虎军规; 开头提到的《高性能网站建设指南》
前端性能优化相当重要,文中说起的是我认为比较重要的几点,之后遇到更好的方案会补充进来。固然你也能够在评论区留言咱们一块儿探讨,有错误的地方欢迎指出。