防抖和節(jié)流的目的都是為了減少不必要的計(jì)算铣猩,不浪費(fèi)資源揖铜,只在適合的時(shí)候再進(jìn)行觸發(fā)計(jì)算。
1. 函數(shù)防抖(debounce)
定義
在事件被觸發(fā)n秒后再執(zhí)行回調(diào)达皿,如果在這n秒內(nèi)又被觸發(fā)天吓,則重新計(jì)時(shí);典型的案例就是輸入搜索:輸入結(jié)束后n秒才進(jìn)行搜索請求峦椰,n秒內(nèi)又輸入的內(nèi)容龄寞,就重新計(jì)時(shí)。實(shí)現(xiàn)原理
函數(shù)防抖的基本思想是設(shè)置一個(gè)定時(shí)器汤功,在指定時(shí)間間隔內(nèi)運(yùn)行代碼時(shí)清楚上一次的定時(shí)器物邑,并設(shè)置另一個(gè)定時(shí)器,知道函數(shù)請求停止并超過時(shí)間間隔才會執(zhí)行滔金。使用場景
文本框輸入搜索(連續(xù)輸入時(shí)避免多次請求接口)代碼實(shí)現(xiàn)
/*
* debounce:實(shí)現(xiàn)函數(shù)的防抖(目的是頻繁觸發(fā)中只執(zhí)行一次)
* @params
* func:需要執(zhí)行的函數(shù)
* wait:檢測防抖的間隔頻率
* immediate:是否是立即執(zhí)行(如果為TRUE是控制第一次觸發(fā)的時(shí)候就執(zhí)行函數(shù)色解,默認(rèn)FALSE是以最后一次觸發(fā)為準(zhǔn))
* @return
* 可被調(diào)用執(zhí)行的函數(shù)
*/
function debounce(func, wait = 500, immediate = false) {
let timer = null;
return function anonymous(...params) {
let now = immediate && !timer;
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
// 執(zhí)行函數(shù):注意保持THIS和參數(shù)的完整度
!immediate ? func.call(this, ...params) : null;
}, wait);
now ? func.call(this, ...params) : null;
};
}
2. 函數(shù)節(jié)流(throttle)
定義
規(guī)定在一個(gè)單位時(shí)間內(nèi),只能觸發(fā)一次函數(shù)餐茵,如果這個(gè)單位時(shí)間內(nèi)觸發(fā)多次函數(shù)科阎,只有一次生效; 典型的案例就是鼠標(biāo)不斷點(diǎn)擊觸發(fā)忿族,規(guī)定在n秒內(nèi)多次點(diǎn)擊只有一次生效萧恕。實(shí)現(xiàn)原理
其原理是用時(shí)間戳來判斷是否已到回調(diào)該執(zhí)行時(shí)間,記錄上次執(zhí)行的時(shí)間戳肠阱,然后每次觸發(fā) scroll 事件執(zhí)行回調(diào)票唆,回調(diào)中判斷當(dāng)前時(shí)間戳距離上次執(zhí)行時(shí)間戳的間隔是否已經(jīng)到達(dá) 規(guī)定時(shí)間段,如果是屹徘,則執(zhí)行走趋,并更新上次執(zhí)行的時(shí)間戳,
使用場景
resize噪伊、scroll簿煌、mousemove等事件觸發(fā)監(jiān)聽
- 代碼實(shí)現(xiàn)
/*
* throttle:實(shí)現(xiàn)函數(shù)的節(jié)流(目的是頻繁觸發(fā)中縮減頻率)
* @params
* func:需要執(zhí)行的函數(shù)
* wait:自己設(shè)定的間隔時(shí)間(頻率)
* @return
* 可被調(diào)用執(zhí)行的函數(shù)
*/
function throttle(func, wait = 500) {
let timer = null,
previous = 0; //記錄上一次操作時(shí)間
return function anonymous(...params) {
let now = new Date(), //當(dāng)前操作的時(shí)間
remaining = wait - (now - previous);
if (remaining <= 0) {
// 兩次間隔時(shí)間超過頻率:把方法執(zhí)行即可
clearTimeout(timer);
timer = null;
previous = now;
func.call(this, ...params);
} else if (!timer) {
// 兩次間隔時(shí)間沒有超過頻率氮唯,說明還沒有達(dá)到觸發(fā)標(biāo)準(zhǔn)呢,設(shè)置定時(shí)器等待即可(還差多久等多久)
timer = setTimeout(() => {
clearTimeout(timer);
timer = null;
previous = new Date();
func.call(this, ...params);
}, remaining);
}
};
}