前端性能优化
结合UX、UI角度、产品设计角度、架构角度、以及开发角度提出的优化方向。各项均为思路和示例可随意拓展,欢迎补充。
文章目录
一、CDN
1. CDN是什么?
CDN(Content Delivery Network,内容分发网络)是指一种通过互联网互相连接的电脑网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。
典型的CDN系统由下面三个部分组成:分发服务系统、负载均衡系统、运营管理系统。
2. CDN的作用什么?
CDN一般会用来托管Web资源(包括文本、图片和脚本等),可供下载的资源(媒体文件、软件、文档等),应用程序(门户网站等)。使用CDN来加速这些资源的访问。
3. CDN的使用场景什么?
-
使用第三方的CDN服务:如果想要开源一些项目,可以使用第三方的CDN服务
-
使用CDN进行静态资源的缓存:将自己网站的静态资源放在CDN上,比如js、css、图片等。可以将整个项目放在CDN上,完成一键部署。
-
直播传送:直播本质上是使用流媒体进行传送,CDN也是支持流媒体传送的,所以直播完全可以使用CDN来提高访问速度。CDN在处理流媒体的时候与处理普通静态文件有所不同,普通文件如果在边缘节点没有找到的话,就会去上一层接着寻找,但是流媒体本身数据量就非常大,如果使用回源的方式,必然会带来性能问题,所以流媒体一般采用的都是主动推送的方式来进行。
实例:在vue-cli4 创建的项目中,配置vue.config.js,让webpack不打包ui库和其他较大的组件,而是通过script标签加入。这部分包含了webpack配置 具体官网连接
const isProduction = process.env.NODE_ENV === 'production' // 判断是否是生产环境
//正式环境不打包公共js
let externals = {}
//储存cdn的文件
let cdn = {
css: [
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.0/theme-chalk/index.min.css' // element-ui css 样式表
],
js: []
}
//正式环境才需要
if (isProduction) {
externals = { //排除打包的js
vue: 'Vue',
'element-ui': 'ELEMENT',
echarts: 'echarts',
}
cdn.js = [
'https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js', // vuejs
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.6.0/index.js', // element-ui js
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.6.0/locale/zh-CN.min.js',
'https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.min.js',
]
}
module.exports = {
//...其它配置
configureWebpack: {
//常用的公共js 排除掉,不打包 而是在index添加cdn,
externals,
//...其它配置
},
chainWebpack: config => {
//...其它配置
// 注入cdn变量 (打包时会执行)
config.plugin('html').tap(args => {
args[0].cdn = cdn // 配置cdn给插件
return args
})
}
//...其它配置
}
index.html文件中动态填入
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>web</title>
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- 引入样式 -->
<% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%=css%>" >
<% } %>
<!-- 引入JS -->
<% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%=js%>"></script>
<% } %>
</head>
<body style="font-size:14px">
<section id="app"></section>
</body>
</html>
二、懒加载
1.懒加载的概念
1.懒加载也叫做延迟加载、按需加载,
2. 懒加载的特点
-
减少无用资源的加载:使用懒加载明显减少了服务器的压力和流量,同时也减小了浏览器的负担。
-
提升用户体验: 如果同时加载较多图片,可能需要等待的时间较长,这样影响了用户体验,而使用懒加载就能大大的提高用户体验。
-
防止加载过多图片而影响其他资源文件的加载 :会影响网站应用的正常使用。
2.图片懒加载
<div class="container">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
</div>
<script>
var imgs = document.querySelectorAll('img');
function lozyLoad(){
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var winHeight= window.innerHeight;
for(var i=0;i < imgs.length;i++){
if(imgs[i].offsetTop < scrollTop + winHeight ){
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}
window.onscroll = lozyLoad();
</script>
3.vue-router懒加载
路由懒加载指的是打包部署时将资源按照对应的页面进行划分,需要的时候加载对应的页面资源,而不是把所有的页面资源打包部署到一块。避免不必要资源加载。
// vue异步组件
{
path: '/home',
name: 'home',
component: resolve => require(['@/components/home'], resolve)
// 或者
const Home = () => import('@/componnets/home');
{
path: '/home',
name: 'home',
component: Home
},
三、节流与防抖
1. 对节流与防抖的理解
- 函数防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。这可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。
- 函数节流是指规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。节流可以使用在 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率。
防抖函数的应用场景:
- 按钮提交场景:防⽌多次提交按钮,只执⾏最后提交的⼀次
- 服务端验证场景:表单验证需要服务端配合,只执⾏⼀段连续的输⼊事件的最后⼀次,还有搜索联想词功能类似⽣存环境请⽤lodash.debounce
节流函数的适⽤场景:
- 拖拽场景:固定时间内只执⾏⼀次,防⽌超⾼频次触发位置变动
- 缩放场景:监控浏览器resize
- 动画场景:避免短时间内多次触发动画引起性能问题
2. 实现节流函数和防抖函数
函数防抖的实现:
function debounce(fn, wait) {
var timer = null;
return function() {
var context = this,
args = [...arguments];
// 如果此时存在定时器的话,则取消之前的定时器重新记时
if (timer) {
clearTimeout(timer);
timer = null;
}
// 设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
}
函数节流的实现:
// 时间戳版
function throttle(fn, delay) {
var preTime = Date.now();
return function() {
var context = this,
args = [...arguments],
nowTime = Date.now();
// 如果两次时间间隔超过了指定时间,则执行函数。
if (nowTime - preTime >= delay) {
preTime = Date.now();
return fn.apply(context, args);
}
};
}
// 定时器版
function throttle (fun, wait){
let timeout = null
return function(){
let context = this
let args = [...arguments]
if(!timeout){
timeout = setTimeout(() => {
fun.apply(context, args)
timeout = null
}, wait)
}
}
}
四、图片优化
1. 如何对项目中的图片进行优化?
- 不用图片。很多时候会使用到很多修饰类图片,其实这类修饰图片完全可以用 CSS 去代替。
- 对于移动端来说,屏幕宽度就那么点,完全没有必要去加载原图浪费带宽。一般图片都用 CDN 加载,可以计算出适配屏幕的宽度,然后去请求相应裁剪好的图片。
- 小图使用 base64 格式
- 将多个图标文件整合到一张图片中(雪碧图)
- 选择正确的图片格式:
- 对于能够显示 WebP 格式的浏览器尽量使用 WebP 格式。因为 WebP 格式具有更好的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量,缺点就是兼容性并不好
- 小图使用 PNG,其实对于大部分图标这类图片,完全可以使用 SVG 代替
- 照片使用 JPEG
五、Webpack优化
主要包含优化打包构建速度和优化代码运行性能还有优化代码调试
1.打包构建速度
- JS代码压缩 terser-webpack-plugin
- CSS代码压缩 css-minimizer-webpack-plugin
- HTML文件压缩 HtmlwebpackPlugin
- 文件大小压缩 compression-webpack-plugin
- 图片压缩 file-loader
2.代码运行性能
- Tree Shaking
- code split
- import 函数,懒加载、预加载
- pwa
3.优化代码调试
- source-map
4.有哪些常⻅的Loader?
- file-loader:把⽂件输出到⼀个⽂件夹中,在代码中通过相对 URL 去引⽤输出的⽂件
- url-loader:和 file-loader 类似,但是能在⽂件很⼩的情况下以 base64 的⽅式把⽂件内容注⼊到代码中去
- source-map-loader:加载额外的 Source Map ⽂件,以⽅便断点调试
- image-loader:加载并且压缩图⽚⽂件 babel-loader:把 ES6 转换成 ES5
- css-loader:加载 CSS,⽀持模块化、压缩、⽂件导⼊等特性
- style-loader:把 CSS 代码注⼊到 JavaScript 中,通过 DOM操作去加载 CSS。
- eslint-loader:通过 ESLint 检查 JavaScript 代码
- svg-sprite-loader :是个用于创建 svg 雪碧图的 Webpack 加载器。这个加载器现在已经被 JetBrains 公司收录和维护了。通的进: sgsprite-oader 会把你引入的 svg 塞到一个 symbol 中,合成一个大的 svg,最后将这大的 sg 放入 body 中symbol 的id如果不特别指定,就是你的文件名。
5.有哪些常⻅的Plugin?
- define-plugin:定义环境变量
- html-webpack-plugin:简化html⽂件创建
- uglifyjs-webpack-plugin:通过 UglifyES 压缩 ES6 代码
- webpack-parallel-uglify-plugin: 多核压缩,提⾼压缩速度
- webpack-bundle-analyzer: 可视化webpack输出⽂件的体积
- mini-css-extract-plugin: CSS提取到单独的⽂件中,⽀持按需加载
- compression-webpack-plugin :开启gzip 文件压缩
- merge-jsons-webpack-plugin :将分散的json组合为一个文件