前言
無論是面試還是在討論瀏覽器優化過程中,都會涉及到去抖動和節流的問題。
總的來說,這二者是一種限制事件觸發頻率的方式。不同的是,節流會指定事件觸發的時間間隔;而去抖動會指定事件不觸發的時間間隔。從結果上來看,節流降低了時間處理的敏感度;而去抖對從觸發事件先儲存起來,等到超過指定事件間隔後,一起傳送。
越來越暈,直接上程式碼:
HTML
<input type="text" oninput="fatch()">
這裡有一個供使用者搜尋使用的input標籤,有一個input事件會觸發的處理函式fatch,這個fatch會根據input的value值向後臺去請求聯想詞。
上面程式碼思路是沒有問題的,但是如果不做觸發限制的話,可能會產生大量的http請求,而這些請求裡面很多可能意義不大,為我們的優化提供了空間;下面,我就採用節流和去抖兩種思路來解決這個問題。(一般針對input這種情況,使用去抖解決;這裡只是方便做程式碼說明)
節流
function jieliu (func, time){//func 執行函式, time 時間間隔
let lastRun = null
return function(){
const now = new Date()
if(now - lastRun > time){
func(...arguments)
lastRun = now
}
}
}
const listener = jieliu(function(value){//監聽函式,指定間隔時間
console.log(value)
}, 1000)
const input = document.querySelector("input")
//呼叫方法
input.addEventListener("input", function(event){
listener(event.target.value)
})
以上是比較簡單的節流實現以及基本的呼叫方式;使用閉包是為了儲存每一次執行的lastRun。基本實現了限制請求頻率的需求,但忽略了最後一個的觸發。
改進如下:
function jieliu (func, time){// 觸發時間間隔>time 傳送請求
let lastRun = null
let timeout = undefined
return function(){
const self = this;
const now = new Date()
if(now - lastRun > time){
if(timeout){
clearTimeout(timeout)
timeout = undefined
}
func.apply(self, arguments)
lastRun = now
}
else{
if(!timeout){
timeout = setTimeout(func.apply(self, arguments), time)
}
}
}
}
加入timeout,判斷是否是最後一次請求。
去抖動
function qudou(func, time){
let timeout = undefined
return function(){
const argu = arguments
const self = this
if(timeout){
clearTimeout(timeout)
timeout = undefined
}else{
timeout = setTimeout(func.apply(this, arguments), time)
}
}
}
以上簡單實現去抖動,同樣,最後一次事件不能夠觸發處理函式。
改進如下:
function qudou(func, time){//判斷連續time時間內不觸發,傳送func請求
let timeout = undefined;
let lastRun = null
return function(){
const self = this
const now = new Date()
if(now - lastRun > time){
func.apply(self, arguments)
}
else {
if(!timeout){
timeout = setTimeout(func.apply(self, arguments), time)
}
else {
clearTimeout(timeout)
timeout = undefined
}
}
lastRun = new Date()
}
}
總結
通篇寫下來,節流主要的實現方式還是通過對比“now”與“lastRun”的時間差,進而減少處理函式的呼叫次數;而防抖還是通過settimeout來延緩處理函式的呼叫時機,進而把多次觸發的結果彙總一起呼叫處理函式。
後記
節流與去抖動兩種方案還是有很大不同的,很多人包括我都很容易搞混。如果大家有更好的解決方案或者需要討論的地方,歡迎在踴躍留言!