防抖和節流(React和Vue版)
阿新 • • 發佈:2020-12-22
技術標籤:js
背景
在公司專案中有購物車功能,最近在測試中碰到一個問題,在點選購物車某個商品的新增或者減少按鈕時,每次的點選後都會請求伺服器,如果快速點選按鈕將會對伺服器造成大量的請求,這顯然會佔用大量的伺服器資源。而防抖和節流是控制事件觸發頻率的方法,可以對此類事件進行很好的限制。
防抖
函式防抖,這裡的抖動就是執行的意思,而一般的抖動都是持續的,多次的。假設函式持續多次執行,我們希望讓它冷靜下來再執行。也就是當持續觸發事件的時候,函式是完全不執行的,等最後一次觸發結束的一段時間之後,再去執行。在我的業務場景裡面就是,一段時間內不管你點選了多少次按鈕,只執行最後一次的點選事件。
React
debounce = (method, delay) => {
//設定一個檢驗setTimeout是否在執行的引數,預設未執行
let {timer = null} = this.state;
//將當前的this賦值給that
//否則在下面函式作用域中this是當前函式作用域,沒有setState方法
let that = this;
return function (...args) {
//檢驗是否有正在執行的定時器方法,如果有,就把上一個定時器廢棄
if (timer) clearTimeout(timer);
//生成一個新的定時器方法重新計數
timer = setTimeout(function () {
method.apply(this, args);
}, delay);
that.setState({timer});
};
};
然後在下面的點選事件中使用這個函式:
let cart = this.debounce(this.cart, 1000);
cart( carts, index, index2);
可以看到商品數量一直變化,只有最後一次點選事件後才執行了請求伺服器的方法。
Vue
function debounce(func,delay){
var timer = null;
return function (...args) {
var that = this;
//如果timer為真,就把上次的timeout銷燬,然後執行最近一次的setTimeout
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(that, args);
}, delay);
};
}
再點選事件中呼叫這個函式:
debounceClick: debounce(function () {
console.log(9999);
}, 5000)
節流
節流的意思是讓函式有節制地執行,而不是毫無節制的觸發一次就執行一次。什麼叫有節制呢?就是在事件觸發後,會先執行一次事件函式,執行之後如果在規定時間間隔內再觸發事件,將不出觸發函式,超過規定的事件間隔後會再次觸發一次,如此往復。
React
throttle = (fn, delay = 3000) => {
//期間間隔執行 節流
let {canRun} = this.state;
let that = this;
// console.log(111, canRun);
return (...rest) => {
if (!canRun) return;
canRun = false;
// console.log(222, canRun);
setTimeout(() => {
fn.apply(this, rest);
canRun = true;
that.setState({canRun});
}, delay);
that.setState({canRun});
};
};
呼叫和防抖一樣:
let cart = this.throttle(this.cart, 2000);
cart(carts, index, index2);
可以看到在點選的時候執行了兩次,這就是防抖和節流的區別,防抖只會執行最後一次的點選事件,而節流是在一段時間內之執行一次。
Vue
export function throttle(fn, wait) {
let canRun = true; // 通過閉包儲存一個標記
return function () {
if (!canRun) return; // 在函式開頭判斷標記是否為true,不為true則return
canRun = false; // 立即設定為false
setTimeout(() => { // 將外部傳入的函式的執行放在setTimeout中
fn.apply(this, arguments);
// 最後在setTimeout執行完畢後再把標記設定為true(關鍵)表示可以執行下一次迴圈了。當定時器沒有執行的時候標記永遠是false,在開頭被return掉
canRun = true;
}, wait);
};
}
呼叫和防抖一樣:
throttleClick: throttle(function () {
console.log(9999);
}, 1000)