函數防抖概念簡述
當持續觸發事件時,一段時間內只能觸發一次。將幾次操作合併爲一此操作進行。比如說有一條賽車通道,賽車通過的時間爲5s,5s之後到達終點,執行領獎操作。
這5s之內只允許一輛賽車在通道內,如果第一輛賽車還在通道內,此時第二輛賽車已經進來了,那麼銷燬第一輛賽車,從第二輛車入場重新計時5s執行領獎操作。
經典應用場景
<input placeholder="請輸入電話" type="number"/>
此input框需要進行一個即時查詢,所以需要實時監聽用戶在input輸入的值。拿到值後發送請求給後臺,返回數據進行電話匹配。
通常的寫法
let telInput = document.querySelector('input');
telInput.addEventListener('input', function(e) {
//如果直接每次發請求,會導致性能問題
//數據請求
$.ajax({})
})
此時存在的問題是,如果這個過程中不斷的發送請求,當請求過多、數據量過大時,瀏覽器很容易卡死或者崩潰,服務器也處理不過來。
此時就要進行函數防抖的處理,如下:
let telInput = document.querySelector('input');
telInput.addEventListener('input', function(e) {
//如果直接每次發請求,會導致性能問題
//數據請求
let timeOut = null;
if(timeOut){
clearTimeout(timeOut)
}else{
timeOut = setTimeout(()=>{
$.ajax({})
},2000)
}
})
此時,當監聽到用戶輸入時,就會進行判斷,如果用戶輸入第一個字符與第二個字符的時間間隔小於2s,那麼從第二個字符開始重新計時。當用戶停下來了,2s過後請求數據。
當然,我們還可以封裝一下,如下:
//fn(方法),wait(等待時間) 都是參數 調用傳進來就可
function antiShake(fn, wait) {
let timeOut = null;
return args => {
if (timeOut) clearTimeout(timeOut)
timeOut = setTimeout(fn, wait);
}
}
調用
let telInput = document.querySelector('input');
//數據請求方法
function demo(){
$.ajax({})
}
telInput.addEventListener('input',antiShake(demo,2000));
函數節流概念簡述
當持續觸發事件時,保證一定時間段內只調用一次事件處理函數。節流,顧名思義,節制流入或流出。比如說水龍頭放水,一旦打開開關,水流就會很快,我們要做的就是限制流出。
經典應用場景
移動端touch事件
<div class="box"></div>
<script>
let box= document.querySelector('.box');
box.addEventListener("touchmove", function (e){
//do something
//ajax({})
//...
})
</script>
如果直接用以上的寫法,touchmove裏的方法或事件,會一直執行,只要手指發生了移動,就會執行。
即使手指移出了 原來的target 元素,但是touchmove 仍然會被一直觸發,而且 target 仍然是原來的 target 元素。
touchmove事件會多次重複觸發,由於移動端計算資源寶貴,儘量保證事件節流。
那麼,思路是怎麼樣的呢?
把整個事件處理器比喻成客運站,如果客運大巴到站就走,那麼路上肯定會發生交通擁堵,而且車大部分是空的,因爲沒給時間上客,虛假繁忙的情況肯定是不好的,那麼怎麼處理呢?
設置一個時間間隔,時間間隔內只允許執行一次,客運站大巴設定一個時間,到點纔會走。
let time = null;
box.addEventListener("touchmove", function (e){
if(!time){
time = setTimeout(()=>{
//do something
//ajax({})
//...
time = null;
},1000)
}
})
同樣的,爲了方便,可以封裝一下
function throttle(event, time) {
let timer = null
//timer狀態要常駐內存,這裏做了一個閉包
return function() {
if (!timer) {
timer = setTimeout(() => {
event();
timer = null
}, time)
}
}
}
調用
function demo(){
//do something
//ajax({})
//...
}
box.addEventListener("touchmove",throttle(demo,2000));
當然,還有第二種辦法,通過時間戳
let throttle = function(func, delay) {
let prev = Date.now();
return function() {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function demo() {
//do something
//ajax({})
//...
}
box.addEventListener('touchmove', throttle(demo, 2000));
FAQ
大家很容易混淆函數防抖與節流的概念,一句話總結:
節流是把一定時間內的多個事件合爲一個
防抖是固定的時間內,事件只允許發生一次
講的很詳細了,如對大家有幫助,歡迎評論轉發。如果有錯誤,敬請指正。
此篇爲原創博文,轉載請註明出處。