这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言~博主看到后会去代替大家踩坑的~
主页: oliver尹的主页
格言: 跌倒了爬起来就好~
目录
一、前言
二、本文内容概述
三、性能优化
3.1 加载性能优化
3.2 构建优化
3.2.1 javascript压缩
3.2.2 CSS压缩
3.3 渲染优化
3.3.1 减少回流
3.3.2 减少布局次数
3.3.3 防抖与节流
3.4 缓存性能优化
3.4.1 浏览器缓存
五、小结
一、前言
最近我司的小伙伴在项目上遇到一些问题,是关于性能上的,因此我们探讨了一些关于前端性能优化方法,再加上自己的一些日常学习笔记,重新整理后有了本文~
耐心看完,你也许有所收获~
二、本文内容概述
本文先是具体分享了一些日常开发中可能遇到的性能优化点或者说是方法,难度:中级;
三、性能优化
3.1 加载性能优化
加载性能优化中最常见的,就是 首屏加载时间的优化,如果是Vue/React的项目这种单页面项目,那站点在首次加载的时候会更加的慢,原因是首次加载的时候会将整个前端项目一下子发送到浏览器...
过长的等待时间,会让用户的耐心消耗殆尽,可能在等待的过程中就直接离开站点了,因此首屏的优化往往就特别重要!
以B站为例,如下图,我们可以看到,当打开B站的首页的时候,请求了83项,共计2.1M的资源大小
但是随着屏幕的滚动,加载的资源会越来越多,如下
这种就是 懒加载 的技术,
说穿了就是只显示可视区域的内容,超出可视区域的内容在未被显示的时候处于没有加载的状态,至于为什么会有偏移量,原因是因为如果正好在页面中出现才进行加载那么会有点晚,用户不能在第一时间看到要看的内容,因此做了一个提前量,一旦元素到达偏移量区域,那么我们就认为用户马上就要看到,应该要主动加载了~
实现的方式也并不复杂,已图片资源为例,将图片地址默认放在自定义属性上,只有当图片进入到偏移量区域时,才将图片上的data-src中的值主动赋值给src;
// 代码层面
<img data-src="图片地址" src="" />
另外,针对Vue/React这种单页应用,我们可以如下进行操作
<!DOCTYPE html>
<html lang="en" id="htmlRoot">
<head>
<title><%= title %></title>
<link rel="icon" href="/favicon.ico" />
</head>
<body>
<div id="app">
// lodaing动画效果
<div class="app-loading">
<div class="app-loading-wrap">
<img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" />
<div class="app-loading-dots">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
<div class="app-loading-title"><%= title %></div>
</div>
</div>
</div>
</body>
</html>
在顶层元素中加上loading的动画效果,我们要知道,Vue/React当资源加载完毕时会主动的去覆盖顶层元素中的内容,我们通过利用这个特性达到了在资源没有加载完毕的时候依然有loading的动画,让用户稍等片刻~
3.2 构建优化
在这之前,我们先问个问题:通过构建上的优化为什么可以提高性能?
我们知道建立请求后开始请求资源的这个过程,如何快速的将所有资源都请求到是个值得关注的过程,那么如果快速的将所有资源都请求到呢?其实就是两点:
- 第一个就是:资源压缩,将资源的体积变小,那么传输的时间就自然变少了;
- 第二个就是:资源合并,将多个资源合并在一起,一次请求就相当于请求到了多个资源,这种自然也可以减少传输时间;
为了达成这两点,就是构建优化,以webpack为例(虽然现在vite等新起的构建工具越来越流行,但webpack其庞大的使用量依然是主流....)
3.2.1 javascript压缩
在webpack上大致有这么几种配置可以达到压缩的效果:
(PS:当使用terser-webpack-plugin进行压缩的时候,这个插件会默认进行多线程压缩,提高压缩速度)
3.2.2 CSS压缩
这里有一个注意点,不要使用style-loader把css直接嵌入到html里面,而是应该独立成css文件,这点很重要,原因也很简单,css的资源是无法并行被加载的,因此会降低渲染的性能;
因此,我们可以使用插件:min-css-extract-plugin 这个插件进行CSS代码的抽取和独立,配置后大致是这样的:
const CSSMinimizerPlugin = require("css-minminzer-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports={
// 其他配置
optimization:{
minimize:true,
minimizer:[new CSSMinimizerPlugin()]
},
plugins:[new MiniCssExtractPlugin()]
}
3.3 渲染优化
前两个优化主要的部分在http请求部分,这一部分则是在资源请求到后,在浏览器渲染进程里渲染成DOM的过程,这个过程大致有以下具体细节:
通过这个大致的流程我们发现,其实界面的渲染是一件挺麻烦的事,最好就是不要动这些已经渲染完成的DOM节点,但事实上,不动是不可能的,用户的日常工作不就是去和界面做交互,一旦交互开始,DOM节点就自然而然会发生各种改变....
3.3.1 减少回流
对于界面的改变,我们可以分成两类:重绘 与 回流,关于这两点我相信小伙伴们肯定很熟悉了,就不多介绍了,相比重绘,回流的影响更大,它是影响了页面上的众多节点的几何属性,因此整个页面需要全部重新走一遍上面的流程,对性能的影响可想而知;
因此,关于这一部分的优化目的其实只有一个:重绘更加消耗性能,尽量减少回流操作;大致有以下属性的修改会影响到回流:
- 几何属性的改变,如:width,height,padding,margin,left,right等;
- DOM树发生变化,如新增,修改,删除dom节点;
- 获取特定属性值,比如offsetTop,scrollTop等;
3.3.2 减少布局次数
值得注意的是,对于下面这种写法我们要禁止:
const dom = document.querySelector(".dom");
dom.style.width="100px";
dom.style.height="100px";
dom.style.border="1px solid #000000";
这种写法它修改了三次DOM的几何属性,因此界面会重新布局3次....这种事不可取的,合理的方式是给dom添加一个class
const dom = document.querySelector(".dom");
dom.classList.add('new-style');
.new-style{
width:100px;
height:100px;
border:1px solid #000000
}
这种添加class的方式它 只会重新布局1次;
3.3.3 防抖与节流
还有针对一些事件,比如
类似这种事件要加上防抖与节流,如果频繁的触发这些事件是必会导致页面的抖动与卡顿,因此无比要加,这里多嘴一句关于防抖与节流,防抖与节流本质上并不是减少事件的触发,而是减少回调函数触发的执行次数,它们的使用场景也有点不一样:
- 节流:节流的含义就是以一个固定的间隔去执行一次函数,比如,1秒内按下了10次键盘,但我们通过节流限定了1秒只请求1次,这样便可以大幅减少请求次数;
- 防抖:防抖的含义是短时间内高频次触发最终会被合并成1次,比如搜索的时候我们快速打了10个字,只有打完后的1秒内没有新文字输入,它才会去请求,一旦在1秒内有新文字输入它则会清空请求事件,不再触发;
防抖与节流的代码网上很多,包括lodash也有现成封装完成的,不再介绍了~
3.4 缓存性能优化
首先是针对 重复请求 的处理,要对已经获取的资源进行重复利用,因为重复的请求会消耗网络带宽,从而影响到用户体验;
3.4.1 浏览器缓存
浏览器缓存分为 强制缓存 和 协商缓存:
- 强制缓存:请求的时候进行缓存字段检查,如果没有过期,直接从浏览器本地缓存中返回资源;
- 协商缓存:在浏览器使用本地缓存之前,向服务器发送请求判断一下本地缓存是否过期;
通常情况下我们一般会以这种流程来做缓存的优先级
五、小结
本文具体介绍了一下性能优化的各个点
- 加载上的优化,目的是通过减少http请求,懒加载技术,来减少首屏的加载时间;
- 构建上的优化,目的是减少资源体积和数量,合理利用主流的构建工具,如webpack等来合并资源,压缩资源;
- 缓存优化,目的是避免重复请求,但对于缓存的策略需要仔细斟酌,毕竟有利有弊;
- 渲染优化,目的是降低高性能的操作,比如减少重绘和回流,合理的代码,以及及时释放资源;