- 防抖
觸發(fā)高頻事件后n秒內(nèi)函數(shù)只會執(zhí)行一次,如果n秒內(nèi)高頻事件再次被觸發(fā)齐邦,則重新計算時間
- 實現(xiàn)方式:每次觸發(fā)事件時設置一個延遲調(diào)用方法椎侠,并且取消之前的延時調(diào)用方法
- 缺點:如果事件在規(guī)定的時間間隔內(nèi)被不斷的觸發(fā),則調(diào)用方法會被不斷的延遲
//防抖debounce代碼:
function debounce(fn) {
let timeout = null; // 創(chuàng)建一個標記用來存放定時器的返回值
return function () {
// 每當用戶輸入的時候把前一個 setTimeout clear 掉
clearTimeout(timeout);
// 然后又創(chuàng)建一個新的 setTimeout, 這樣就能保證interval 間隔內(nèi)如果時間持續(xù)觸發(fā)侄旬,就不會執(zhí)行 fn 函數(shù)
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, 500);
};
}
// 處理函數(shù)
function handle() {
console.log(Math.random());
}
// 滾動事件
window.addEventListener('scroll', debounce(handle));
- 節(jié)流
高頻事件觸發(fā)肺蔚,但在n秒內(nèi)只會執(zhí)行一次,所以節(jié)流會稀釋函數(shù)的執(zhí)行頻率
- 實現(xiàn)方式:每次觸發(fā)事件時儡羔,如果當前有等待執(zhí)行的延時函數(shù)宣羊,則直接return
//節(jié)流throttle代碼:
function throttle(fn) {
let canRun = true; // 通過閉包保存一個標記
return function () {
// 在函數(shù)開頭判斷標記是否為true,不為true則return
if (!canRun) return;
// 立即設置為false
canRun = false;
// 將外部傳入的函數(shù)的執(zhí)行放在setTimeout中
setTimeout(() => {
// 最后在setTimeout執(zhí)行完畢后再把標記設置為true(關鍵)表示可以執(zhí)行下一次循環(huán)了汰蜘。
// 當定時器沒有執(zhí)行的時候標記永遠是false仇冯,在開頭被return掉
fn.apply(this, arguments);
canRun = true;
}, 500);
};
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));
總結:
函數(shù)防抖:將多次操作合并為一次操作進行。原理是維護一個計時器族操,規(guī)定在delay時間后觸發(fā)函數(shù)苛坚,但是在delay時間內(nèi)再次觸發(fā)的話,就會取消之前的計時器而重新設置色难。這樣一來泼舱,只有最后一次操作能被觸發(fā)。
函數(shù)節(jié)流:使得一定時間內(nèi)只觸發(fā)一次函數(shù)枷莉。原理是通過判斷是否有延遲調(diào)用函數(shù)未執(zhí)行娇昙。
區(qū)別: 函數(shù)節(jié)流不管事件觸發(fā)有多頻繁,都會保證在規(guī)定時間內(nèi)一定會執(zhí)行一次真正的事件處理函數(shù)笤妙,而函數(shù)防抖只是在最后一次事件后才觸發(fā)一次函數(shù)冒掌。 比如在頁面的無限加載場景下噪裕,我們需要用戶在滾動頁面時,每隔一段時間發(fā)一次 Ajax 請求股毫,而不是在用戶停下滾動頁面操作時才去請求數(shù)據(jù)膳音。這樣的場景,就適合用節(jié)流技術來實現(xiàn)铃诬。