函数节流(throttle)与 函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。
通俗易懂版介绍防抖和节流
防抖:函数不会立即执行,而是等待一段时间(假设需要等待5s),如果在5s内,再次触发事件,倒计时立刻归零,会再次等待5s后,函数才会被执行。当事件被频繁触发时,函数的执行会不断的被延迟。
应用场景:
- 搜索框联想场景:输入框频繁输入内容进行搜索
下面就来实现debounce~
思路:每次触发事件时都取消之前的定时器 (重在清除)
1.基础版本(必须掌握的版本):
const debounce = (fn, delay) => {
let timer = null;
return function (...args) {
// 清除上一次的执行
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay);
}
}
2.有时后我们想实现第一次触发事件的时候让函数立即执行,并且中间停了delay时间后再次触发事件时候也让函数立即执行。实现如下:
// immediate用来表示是否立即执行
const debounce2 = (fn, delay, immediate = false) => {
let isInvoke = false; // 是否已经执行了一次
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer)
if (immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
} else {
timer = setTimeout(() => {
fn.apply(this, args)
isInvoke = false
}, delay);
}
}
}
3.如果当我们已经触发了事件,但是我们想取消事件的时候,实现如下:
const debounce = (fn, delay, immediate = false) => {
let isInvoke = false; // 是否执行了一次
let timer = null;
let _debounce = function (...args) {
clearTimeout(timer)
if (immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
} else {
timer = setTimeout(() => {
fn.apply(this, args)
isInvoke = false
}, delay);
}
}
// 增加取消功能
_debounce.cancel = function () {
if (timer) clearTimeout(timer)
}
return _debounce
}
到这里,防抖的功能基本已经完善了~
节流:高频触发事件,函数会以一个固定的频率去执行。
应用场景:
- 按钮提交场景:频繁点击按钮,触发事件
下面就来实现基础版本的节流:
思路:当当前触发时间与上一次函数被触发时的时间间隔大于等于固定频率时间 的时候才会让函数执行
基础版本(必须掌握版本):
/**
*
* @param {*} fn 需要执行的函数
* @param {*} interval 频率
* @returns
*/
const throttle = (fn, interval) => {
let lastTime = 0
let _throttle = function (...args) {
let nowTime = new Date().getTime();
if (nowTime - lastTime >= interval) {
fn.apply(this, args)
lastTime = nowTime
}
}
return _throttle
}
其他版本后续会补充~
总结
- 函数防抖:
限制执行次数,多次密集的触发只执行一次
- 将几次操作合并为一次操作进行。原理是维护一个计时器,规定在
delay
时间后触发函数,但是在delay
时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
- 将几次操作合并为一次操作进行。原理是维护一个计时器,规定在
- 函数节流:
限制执行的频率,按照一定的时间间隔有节奏的执行
- 使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。