深入淺出js函數防抖與節流

函數防抖概念簡述

當持續觸發事件時,一段時間內只能觸發一次。將幾次操作合併爲一此操作進行。比如說有一條賽車通道,賽車通過的時間爲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

大家很容易混淆函數防抖與節流的概念,一句話總結:

節流是把一定時間內的多個事件合爲一個
防抖是固定的時間內,事件只允許發生一次

講的很詳細了,如對大家有幫助,歡迎評論轉發。如果有錯誤,敬請指正。
此篇爲原創博文,轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章