以下場景往往由于事件頻繁被觸發(fā)益兄,因而頻繁執(zhí)行DOM操作弓柱、資源加載等重行為务豺,導(dǎo)致UI停頓甚至瀏覽器崩潰。
window對象的resize debounce
scroll事件 throttle
拖拽時的mousemove事件 debounce
射擊游戲中的mousedown喘批、keydown事件 debounce
文字輸入撩荣、自動完成的keyup事件 debounce
實際上對于window的resize事件,實際需求大多為停止改變大小n毫秒后執(zhí)行后續(xù)處理饶深;而其他事件大多的需求是以一定的頻率執(zhí)行后續(xù)處理餐曹。針對這兩種需求就出現(xiàn)了debounce和throttle兩種解決辦法。
debounce
當(dāng)頻繁改變窗口大小時敌厘,你會發(fā)現(xiàn) fn壓根沒有被調(diào)用過台猴!直到你停下來后,fn才會被調(diào)用一次俱两。
const debounce = (fn, ms = 0) => {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), ms);
};
};
// 使用
window.addEventListener(
'resize',
debounce(() => {
console.log(window.innerWidth);
}, 1000)
);
throttle
當(dāng)頻繁改變窗口大小時饱狂,throttle 會保證在每 wait時間調(diào)用 fn一次。
(我們的直觀感覺是使用 throttle 方法相比于 debounce 方法事件觸發(fā)的頻率更高一些)
const throttle = (fn, wait) => {
let inThrottle, lastFn, lastTime;
return function() {
const context = this,
args = arguments;
if (!inThrottle) {
fn.apply(context, args);
lastTime = Date.now();
inThrottle = true;
} else {
clearTimeout(lastFn);
lastFn = setTimeout(function() {
if (Date.now() - lastTime >= wait) {
fn.apply(context, args);
lastTime = Date.now();
}
}, wait - (Date.now() - lastTime));
}
};
};
參考鏈接:
腳本之家:debounce與throttle的簡單版
博客:debounce與throttle的深入版
掘金: 函數(shù)節(jié)流與函數(shù)防抖
debounce 與throttle 的適用場景
奇舞周刊的總結(jié)