一、防抖
防抖函數的作用
防抖函數的作用就是控制函數在一定時間內的執行次數。防抖意味着 N 秒內函數只會被執行一次,如果 N 秒內再次被觸發,則 重新 計算延遲時間。
防抖函數的實現
- 事件第一次觸發時,timeout 是 null,調用 later(),若 immediate 爲true,那麼立即調用 func.apply(this, params);如果 immediate 爲 false,那麼過 wait 之後,調用 func.apply(this, params)。
- 事件第二次觸發時,如果 timeout 已經重置爲 null (即 setTimeout 的倒計時結束),那麼流程與第一次觸發時一樣,若 timeout 不爲 null (即 setTimeout 的倒計時未結束),那麼清空定時器,重新開始計時。
function debounce(func, wait, immediate = true) {
let timeout, result;
// 延遲執行函數
const later = (context, args) => setTimeout(() => {
timeout = null;// 倒計時結束
if (!immediate) {
// 執行回調
result = func.apply(context, args);
context = args = null;
}
}, wait);
let debounced = function (...params) {
if (!timeout) {
timeout = later(this, params);
if (immediate) {
// 立即執行
result = func.apply(this, params);
}
} else {
clearTimeout(timeout);
// 函數在每個等待時延的結束被調用
timeout = later(this, params);
}
return result;
}
// 提供在外部清空定時器的方法
debounced.cancel = function () {
clearTimeout(timeout);
timeout = null;
};
return debounced;
};
immediate 爲 true 時,表示函數在每個等待時延的開始被調用。immediate 爲 false 時,表示函數在每個等待時延的結束被調用。
防抖的應用場景
搜索框輸入查詢,如果用戶一直在輸入中,沒有必要不停地調用去請求服務端接口,等用戶停止輸入的時候,再調用,設置一個合適的時間間隔,有效減輕服務端壓力。
表單驗證。
按鈕提交事件。
瀏覽器窗口縮放,resize 事件 (如窗口停止改變大小之後重新計算佈局) 等。
二、節流
節流函數的作用
節流函數的作用是規定一個單位時間,在這個單位時間內最多隻能觸發一次函數執行,如果這個單位時間內多次觸發函數,只能有一次生效。
節流函數的實現
function throttle(func, wait, options = {}) {
var timeout, context, args, result;
var previous = 0;
var later = function () {
previous = options.leading === false ? 0 : (Date.now() || new Date().getTime());
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function () {
var now = Date.now() || new Date().getTime();
if (!previous && options.leading === false) previous = now;
//remaining 爲距離下次執行 func 的時間
//remaining > wait,表示客戶端系統時間被調整過
var remaining = wait - (now - previous);
context = this;
args = arguments;
//remaining 小於等於 0,表示事件觸發的間隔時間大於設置的 wait
if (remaining <= 0 || remaining > wait) {
if (timeout) {
// 清空定時器
clearTimeout(timeout);
timeout = null;
}
// 重置 previous
previous = now;
// 執行函數
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
throttled.cancel = function () {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
}
禁用第一次首先執行,傳遞 {leading: false} ;想禁用最後一次執行,傳遞 {trailing: false}。
節流的應用場景
按鈕點擊事件。
拖拽事件。
onScoll。
計算鼠標移動的距離 (mousemove)。
轉載自:《前端之巔》微信公衆號
END