簡介
防抖與節流都是用來限制使用者頻發觸發事件的機制,下面我將簡單介紹一下,防抖與節流的區別及其應用場景
防抖
當使用者觸發某次事件後,若在規定時間內不再觸發該事件,則這個事件才會被真正響應。我們稱這樣的機制為防抖
舉例說明
現規定一輛大巴,從最後一位上車人的時間算起,在等待十分鐘後,才允許發車。
若我們設定最後一個上車人的時間設為Tn,那麼發車的時間則為Tn + 10min。
在上述例子中,我們不難發現,大巴發車的時間是不固定的,是隨著最後一位上車人的時間而動態改變的。如果大巴在等待發車的過程中,不斷有人上車,那麼大巴真正的發車時間則不斷向後推移,並且始終與最後一位上車人的時間保持著十分鐘的時間差。
觸發與響應
我們可以將人上車
這一動作比作事件的觸發,而大巴發車
則比作事件的響應。我們可以知道,在防抖
機制裡面,事件的響應時間
(也就是事件真正開始執行的時間)是隨這個事件最後被觸發的時間
而發生變化的。
我們再做一個假設,現有一個按鈕,當使用者點選這個按鈕時,並且要求在十秒內不再點選這個按鈕,才會向後臺傳送請求。
我們設定觀察時間為三十秒,T代表使用者點選按鈕,R代表向後臺傳送請求
一、若使用者每隔五秒點選一次按鈕,則事件時間示例圖下:
由上圖,我們可以看到,因為使用者每次點選按鈕的時間間隔不足十秒,所以在這觀察的三十秒內並不會有向後臺傳送的請求。
二、若使用者每隔十五秒點選一次按鈕,則事件時間示例圖下:
而這一次,當我們將使用者每次點選按鈕的時間間隔保持在十秒以上時,則一共向後臺傳送了兩次請求:R1和R2。
程式碼示例
只要簡單的幾行程式碼便可實現防抖機制
/**
* @desc 函式防抖
* @param func 函式
* @param wait 延遲執行毫秒數
*/
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
Tips:
apply()
方法是用來改變this
指向的
在JavaScript中,防抖
主要是通過setTimeout
來實現的。當事件被觸發時,則建立一個計時器,只有當約定的時間到了才會真正執行事件,但是當事件還未執行,而這個事件又再次被觸發了,則將上一計時器清除,重新建立一個新計時器,也就是重新計算時間的意思。
在Vue中的使用
以Vue為例,實現我們開頭舉的大巴發車的例子
<template>
<div id="app">
<button @click="addPeople">有人上車</button>
<h1>發車次數:{{ runNum }}</h1>
<h1>車上人數:{{ people }}</h1>
<h1>距離最後一個人上車已等待:{{ time }}秒</h1>
</div>
</template>
<script>
/**
* @desc 函式防抖
* @param func 函式
* @param wait 延遲執行毫秒數
*/
function debounce(func, wait) {
let timeout
return function () {
let context = this
let args = arguments
if (timeout) clearTimeout(timeout)
timeout = setTimeout(function() {
func.apply(context, args)
}, wait)
}
}
export default {
data() {
return {
runNum: 0, // 發車次數
people: 0, // 上車人數
time: 0,
interval: ''
}
},
watch: {
people: debounce(function (val) {
this.runNum++
clearInterval(this.interval)
}, 10000)
},
methods: {
addPeople () {
this.clearTime()
this.people++
this.startTime()
},
startTime () {
this.interval = setInterval(() => {
this.time++
}, 1000)
},
clearTime () {
this.time = 0
clearInterval(this.interval)
}
}
}
</script>