前端性能优化
没有标准答案,越全面越好,如果做不到,就尽量从前端角度考虑
原则
- 多使用内存,缓存(以空间换时间,这种思想也适用于后台)访问频繁,变化不大
- 减少 CPU 计算量,减少网络加载耗时
入手
1、 提升加载速度
- 减少资源体积:压缩代码(如QQ的图片压缩等)
- 减少访问次数:合并代码,SSR服务端渲染、缓存等
- 使用更快的网络:CDN
- CSS 放在 head,JS 放在 body 最下面
- 尽早开始执行 JS,用 DOMContentLoaded 触发
- 懒加载(图片懒加载,上滑懒加载)
2、 提升渲染速度
- 对 DOM 查询进行缓存
- 拼单 DOM 操作,合并到一起插入 DOM 结构
- 节流 throttle 防抖 debounce
防抖
示例:输入框的 keyup 事件
防抖处理
下面代码使用定时器对 keyup 事件进行了防抖处理,核心原则就是
- 当用户 1000ms 之内没有再次输入,就对文本框的内容进行处理(这里只是简单的输出)
- 如果用户在 1000ms 之内继续输入,则清除上次的定时器,自然就不会对文本框内容进行处理了
- 也就是说,最终只会对最后一次输入进行处理
- 试想,如果是实时验证用户名是否可用的需求,做了防抖处理后,能够大大减轻服务器的压力,减少请求次数
代码演示:
<!DOCTYPE html>
<html lang="en">
<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>防抖</title>
</head>
<body>
<input type="text" name="" id="userName">
<script>
const txt_userName = document.querySelector('#userName')
txt_userName.addEventListener('keyup', debounce(() => {
console.log(this);
console.log(txt_userName.value);
}))
// 封装防抖函数
function debounce(callback, delay = 1000) {
let timer = null
return function () {
if (timer) {
// 可取消由 setTimeout() 方法设置的 timeout
clearTimeout(timer)
}
timer = setTimeout(() => {
// 事件处理代码
callback && callback()
timer = null
}, delay)
}
}
</script>
</body>
</html>
节流
示例:拖拽元素
- 拖拽元素时,要随时拿到被拖拽元素的位置
- 直接用 drag 事件,会频繁触发,很容易导致卡顿
- 节流:无论拖拽速度多快,都会每隔 100ms 触发一次
<!DOCTYPE html>
<html lang="en">
<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>节流</title>
<style>
.box {
width: 200px;
height: 150px;
background-color: rgb(175, 95, 250);
}
</style>
</head>
<body>
<div class="box" draggable="true"></div>
<script>
const box = document.querySelector('.box')
box.addEventListener('drag', throttling((e) => {
console.log(e);
}))
function throttling(callback, delay=1000) {
let timer = null
return function() {
if(timer) return
timer = setTimeout(() => {
callback && callback.apply(this,arguments)
timer = null
},delay)
}
}
</script>
</body>
</html>
图片懒加载
css样式
<style>
body {
width: 100%;
height: 100%;
}
img {
width: 200px;
height: 280px;
}
</style>
html代码
<body>
<div>
<div>
<h2>白敬亭也太帅了吧</h2>
<p>今天又是被小白帅炸的一天哦!!!啦啦啦啦啦~~~~~</p>
<img src="" alt="" data-src="https://www.77wenyu.com/uploads/img1/20200712/8cf365eed29433fdf0a28882491da083.jpg">
</div>
<div>
<h2>白敬亭也太帅了吧</h2>
<p>今天又是被小白帅炸的一天哦!!!啦啦啦啦啦~~~~~</p>
<img src=""
data-src="https://star-img.idol001.com/atlas/7177/images/2018/2/6/C58r63d4j41517896392282.jpg/default-w720"
alt="">
</div>
<div>
<h2>白敬亭也太帅了吧</h2>
<p>今天又是被小白帅炸的一天哦!!!啦啦啦啦啦~~~~~</p>
<img src="" alt=""
data-src="https://uploadfile.bizhizu.cn/up/92/d4/87/92d487a2c3f10ad62061bfccbbeacff7.jpg.source.jpg">
</div>
<div>
<h2>白敬亭也太帅了吧</h2>
<p>今天又是被小白帅炸的一天哦!!!啦啦啦啦啦~~~~~</p>
<img src="" data-src="https://c-ssl.duitang.com/uploads/item/201803/14/20180314090645_gprdv.jpg" alt="">
</div>
</div>
</body>
js代码
<script>
var imgArr = document.querySelectorAll('img');
var n = 0; //存储图片加载到的位置,避免每次都从第一张图片开始遍历
// 图片懒加载
function lazyLoad() {
// 可视区域高度
const seeHeight = window.innerHeight
for (var i = n; i < imgArr.length; i++) {
if (imgArr[i].offsetTop < seeHeight + window.pageYOffset) {
if (imgArr[i].getAttribute('src') == '') {
imgArr[i].src = imgArr[i].getAttribute('data-src')
}
n = i + 1
}
}
}
lazyLoad()
// 滚屏函数
window.onscroll = throttling(lazyLoad)
// 节流函数
function throttling(callback, delay = 1000) {
let timer = null
return function () {
if (timer) return
timer = setTimeout(() => {
callback()
timer = null
}, delay)
}
}
</script>