使用rxjs以及javascript解決前端的防抖和節流


JavaScript實現方式:

防抖

觸發高頻事件后 n 秒內函數只會執行一次,如果 n 秒內高頻事件再次被觸發,則重新計算時間;
思路:每次觸發事件時都取消之前的延時調用方法:

舉個例子:做一個自動查詢的功能
假裝下面的代碼是從服務器獲取的數據(下面會用到):// 假裝這是個接口function getData(val){    returnnew Promise(function(resolve, reject){

        setTimeout(function(){
            if(!val){resolve([]);return;}
            var json = [
                {name:"蕭山國際機場",jianpin:"xsgjjc",threeCode:"xjc"},
                {name:"北京南苑機場",jianpin:"bjnyjc",threeCode:"byc"},
                {name:"上海虹橋機場",jianpin:"shhqjc",threeCode:"hcg"},
                {name:"成都機場",jianpin:"cdjc",threeCode:"cjc"}
            ];
            var newJson = json.filter(function(item){
                return item.name.indexOf(val)==0||item.jianpin.indexOf(val)==0||item.threeCode.indexOf(val)==0
            });
            resolve(newJson);
        },1000)
    })
}

 

在文本框輸入關鍵字去服務器實時請求對應的數據,如下代碼; <body>
    <input type="text" placeholder="簡拼/漢字/三字碼" id="test"/>
    <script>
        var $test = document.getElementById('test');
        $test.onkeyup =autoSearch;
        function autoSearch(){
            var val = $test.value;
            getData(val).then(function(res){console.log(res)})
        }   
    </script>
</body>

 

結果如下圖,在運行的時候會發現存在一個問題:這個函數的默認執行頻率太高了,高到什么程度呢?我們輸入"蕭山",函數執行了9次!,然而我們需要的只是最后一次.

然而實際上我們並不需要如此高頻的反饋,畢竟瀏覽器和服務器的性能是有限的,所以接着討論如何優化這種場景。

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>

結果:



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM