有这么一种场景:某个页面表单按钮设置了点击提交事件,有时因为网络不好,点击后后台服务端很久才返回信息,然而用户因等待许久已经多次点击导致多次发送数据,实际上服务器只需要一次发送的数据即可
又比如说这么一种场景:某个页面设置监听的resize事件,一旦resize则重新渲染页面,有时用户会慢慢的拖动导致不断触发resize事件,频繁的触发重新渲染导致页面出现问题,实际上只需要在一段时间内执行最后一次resize事件的重新渲染即可
解决诸如上述场景的问题,可以使用防抖
和节流
防抖(Debounce)和节流(Throttle)是两种常用的优化JavaScript性能的技术
防抖是指在事件被触发后,等待一段时间后才执行回调函数。如果在这段时间内又触发了该事件,则重新计时。防抖常用于处理频繁触发的事件,如窗口大小调整、搜索框输入等。通过防抖可以减少事件回调的执行次数,从而提高性能和减少不必要的资源消耗
示例代码如下:
function debounce(func, delay) {
let timeoutId;
return function() {
clearTimeout(timeoutId);
timeoutId = setTimeout(func, delay);
}
}
function handleResize() {
// 处理窗口大小调整的逻辑
}
window.addEventListener('resize', debounce(handleResize, 200));
防抖较为简单,就是等待一段时间后执行
节流是指在一段时间内只允许函数执行一次。如果在这段时间内多次触发该函数,只有某一次触发会执行,其余触发会被忽略。节流常用于处理高频率触发的事件,如滚动事件、鼠标移动事件等。通过节流可以控制函数的执行频率,从而提高性能和避免过多的计算或渲染
示例代码如下:
function throttle(func, delay) {
let lastExecTime = 0;
return function() {
const currentTime = Date.now();
if (currentTime - lastExecTime > delay) {
func();
lastExecTime = currentTime;
}
}
}
function handleScroll() {
// 处理滚动事件的逻辑
}
window.addEventListener('scroll', throttle(handleScroll, 200));
测试如下,未设置节流时,下图页面滑动触发11次scroll
处理函数,设置节流后触发3次scroll
处理函数:
未设置节流window.addEventListener('scroll', handleScroll)
:
设置节流window.addEventListener('scroll', throttle(handleScroll, 200))
:
上述节流代码设置为只执行一段时间内的第一次,节流也可以设置为只执行最后一次,示例代码如下:
function throttle(func, delay) {
let timeoutId;
let lastExecTime = 0;
return function () {
const currentTime = Date.now();
if (currentTime - lastExecTime > delay) {
func();
lastExecTime = currentTime;
} else {
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
func();
lastExecTime = currentTime;
}, delay-(currentTime - lastExecTime));
}
}
}
function handleScroll() {
// 处理滚动事件的逻辑
console.log('scroll');
}
window.addEventListener('scroll', throttle(handleScroll, 200));
防抖是等待一段时间后执行,且只执行最后一次
节流是一段时间内只执行一次,执行第一次或最后一次都行
Lodash 是一个 JavaScript 实用工具库,包含了防抖和节流函数
修改防抖部分代码:
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
<script>
function handleResize() {
// 处理窗口大小调整的逻辑
console.log('resize');
}
window.addEventListener('resize', _.debounce(handleResize, 200));
</script>
修改节流部分代码:
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
<script>
function handleScroll() {
// 处理滚动事件的逻辑
console.log('scroll');
}
window.addEventListener('scroll', _.throttle(handleScroll, 200, { trailing: false }));
// trailing: false 表示禁用最后一次执行,即执行第一次
</script>
更为具体的函数API解释可查看文档:
[1] 前端性能优化篇: 防抖和节流 - 掘金 (juejin.cn)