JavaScript實現方式:
防抖
觸發高頻事件后 n 秒內函數只會執行一次,如果 n 秒內高頻事件再次被觸發,則重新計算時間;
思路:每次觸發事件時都取消之前的延時調用方法:
舉個例子:做一個自動查詢的功能
假裝下面的代碼是從服務器獲取的數據(下面會用到):// 假裝這是個接口function getData(val){ returnnew Promise(function(resolve, reject){
然而實際上我們並不需要如此高頻的反饋,畢竟瀏覽器和服務器的性能是有限的,所以接着討論如何優化這種場景。
function debounce(fn,delay){ let timer = null //閉包 return function() { if(timer){ clearTimeout(timer) } timer = setTimeout(fn,delay) } } // 改寫上面的代碼 ... $test.onkeyup = debounce(autoSearch,1000); ...
再次運行結果就是我們想要的結果了:
節流
高頻事件觸發,但在 n 秒內只會執行一次,所以節流會稀釋函數的執行頻率。
思路:每次觸發事件時都判斷當前是否有等待執行的延時函數。
還是上面的例子:如果某個用戶閑的蛋疼,一直按着鍵盤不撒手,那么只要她在1秒內重新按了鍵盤,就永遠不會有結果輸出,但是我們還想要在某個時間間隔之后給出反饋呢
使用方法跟debounce一樣。代碼邏輯也類似。在觸發時超過間隔時間interval ms則執行。否則不執行。if判斷中的setTimeout是保證最后一次事件觸發后能夠調用,所以每次執行沒到間隔時間時先清除timer,再重新啟動timer。而在達到間隔時間時執行函數。代碼邏輯也很簡單,不用多說,相信聰明的你一看就能明白。
function throttle(fn,interval){ var last; var timer; var interval=interval||200; return function(){ var th=this; var args=arguments; var now=+new Date(); if(last&&now-last<interval){ clearTimeout(timer); timer=setTimeout(function(){ last=now; fn.apply(th,args); },interval); }else{ last=now; fn.apply(th,args); } } } // 改寫上面的代碼 ... $test.onkeyup = throttle(autoSearch,1000); ...
運行結果就是我們想要的結果了(不管文本框輸入什么內容,沒1秒輸出一次結果):
rxjs實現方式
使用rxjs,使用起來更方便(要記得要安裝或者引入rxjs哦)
使用debounceTime(防抖)和throttleTime(節流)操作符,對流進行限制,然后再訂閱符合規則的流,輸出想要的數據即可,
rxjs的可以參考官方文檔.https://cn.rx.js.org/
也可以查看Rx觀測的交互圖:
debounceTime: https://rxmarbles.com/#debounceTime
throttleTime:https://rxmarbles.com/#throttleTime
例子:
<head> <script src="https://cdn.bootcss.com/rxjs/6.0.0-alpha.3/Rx.min.js"></script> </head> <body> 防抖:<input type="text" placeholder="簡拼/漢字/三字碼" id="debounce"/><br/><br/> 節流:<input type="text" placeholder="簡拼/漢字/三字碼" id="throttle"/> <script> var $debounce = document.getElementById('debounce'); var $throttle = document.getElementById('throttle'); const debounce$ = Rx.Observable.fromEvent($debounce, 'input'); const throttle = Rx.Observable.fromEvent($throttle, 'input'); // 節流 debounce$ .debounceTime(1000) .subscribe(function (e) { var value = e.target.value; console.log('防抖:'+value) }); // 防抖 throttle .throttleTime(1000) .subscribe(function (e) { var value = e.target.value; console.log('節流:'+value) }); </script> </body>