一.什么是函數(shù)防抖
函數(shù)防抖(debounce)悟狱,就是指觸發(fā)事件后,在 n 秒內(nèi)函數(shù)只能執(zhí)行一次析蝴,如果觸發(fā)事件后在 n 秒內(nèi)又觸發(fā)了事件懂诗,則會重新計算函數(shù)延執(zhí)行時間(在這里和函數(shù)節(jié)流區(qū)分一下,函數(shù)節(jié)流是在觸發(fā)完事件之后的一段時間之內(nèi)不能再次觸發(fā)事件)抛虏。
二.函數(shù)防抖的實現(xiàn)思路
在觸發(fā)事件的時候博其,設(shè)置一個定時器,如果之前就已經(jīng)觸發(fā)過該事件了迂猴,就清除之前設(shè)置的定時器慕淡,重新設(shè)置一個定時器,如果在觸發(fā)事件之后沒有再次觸發(fā)事件沸毁,那么就等待計時結(jié)束執(zhí)行函數(shù)峰髓。
三.代碼實現(xiàn)
function debounce(fn, delay) {
if(typeof fn!=='function') {
throw new TypeError('fn不是函數(shù)')
}
let timer; // 維護一個 timer
return function () {
var _this = this; // 取debounce執(zhí)行作用域的this(原函數(shù)掛載到的對象)
var args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
fn.apply(_this, args); // 用apply指向調(diào)用debounce的對象,相當于_this.fn(args);
}, delay);
};
}
四.函數(shù)防抖的使用場景
1.搜索框搜索輸入息尺。只需用戶最后一次輸入完携兵,再發(fā)送請求;
2.用戶名搂誉、手機號徐紧、郵箱輸入驗證;
3.瀏覽器窗口大小改變后炭懊,只需窗口調(diào)整完后浪汪,再執(zhí)行 resize 事件中的代碼,防止重復(fù)渲染凛虽。
五.防抖的立即執(zhí)行與非立即執(zhí)行
函數(shù)防抖其實是分為 “立即執(zhí)行版” 和 “非立即執(zhí)行版” 的死遭,根據(jù)字面意思就可以發(fā)現(xiàn)他們的差別,所謂立即執(zhí)行版就是 觸發(fā)事件后函數(shù)不會立即執(zhí)行凯旋,而是在 n 秒后執(zhí)行呀潭,如果在 n 秒內(nèi)又觸發(fā)了事件钉迷,則會重新計算函數(shù)執(zhí)行時間。 而 “非立即執(zhí)行版” 指的是 觸發(fā)事件后函數(shù)會立即執(zhí)行钠署,然后 n 秒內(nèi)不觸發(fā)事件才能繼續(xù)執(zhí)行函數(shù)的效果
/**
* @desc 函數(shù)防抖---“立即執(zhí)行版本” 和 “非立即執(zhí)行版本” 的組合版本
* @param func 需要執(zhí)行的函數(shù)
* @param wait 延遲執(zhí)行時間(毫秒)
* @param immediate---true 表立即執(zhí)行糠聪,false 表非立即執(zhí)行
**/
function debounce(func,wait,immediate) {
let timer;
return function () {
let context = this;
let args = arguments;
if (timer) clearTimeout(timer);
if (immediate) {
var callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait)
if (callNow) func.apply(context, args)
} else {
timer = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}