JS防抖和節流


  前言

 在網頁實際運行的某些場景下,有些事件會不間斷的被觸發,如scroll事件,而不像我們想象中的,滾動一次觸發一次,稍微滾動一下就會觸發n多次scroll事件。如下:

window.onscroll = function (){
        console.log(123);
    }  //監聽滾動條滑動

 我只是輕微的滾動了一下滾動條就觸發了這么多次的scroll事件,這種情況下,由於過於頻繁地DOM操作和資源加載,嚴重影響了網頁性能,甚至會造成瀏覽器崩潰。

 此時,我們可以采用 debounce(防抖)和 throttle(節流)的方式來減少調用頻率,同時又不影響實際效果。

 

  防抖

 防抖通過設置setTimeout定時器的方式延遲執行,當快速多次點擊的時候,每一次都會重置定時器,只有你一段時間都不點擊時定時器才能到達條件並執行事件函數。即如果觸發事件后在 n 秒內又觸發了事件,則會重新計算函數延執行時間。

 如下,我們模擬一個表單提交的例子,多次快速點擊提交后只會執行一次:

<input type="submit" id="btn" value="提交">
<script>
    var btn = document.getElementById('btn');
    // 點擊后觸發debounce()函數,第一個參數為真實要執行的函數,第二個參數為定時器延遲時間
    btn.addEventListener('click',debounce(submit,1000));
    //真實要執行的函數
    function submit(e){
        console.log("提交成功!");
        console.log(this)
        console.log(e);
    }
    //防抖函數
    function debounce(fn,delay){
        //設置time為定時器
        var time = null;
        //閉包原理,返回一個函數
        return function (e){
            //如果定時器存在則清空定時器
            if(time){
                clearTimeout(time);
            }
            //設置定時器,規定時間后執行真實要執行的函數
            time = setTimeout(() => {//此箭頭函數里的this指向btn這個按鈕
                fn.call(this,arguments);//改變真實要執行函數的this指向,原submit函數里面的this指向window
            },delay);
        }
    }
</script>

 運行后,狂點提交按鈕停下來后只會執行一次,而不會出現多次點擊而多次提交。對於代碼中的閉包還有箭頭函數的this指向問題不清楚的,可以翻看我的這兩篇:閉包箭頭函數

 

  節流

 節流其實就很好理解了,減少一段時間的觸發頻率。簡單來說,就是你一直狂點不停的話,它會每隔一定時間就執行一次。它與防抖最大的區別就是,無論事件觸發多么頻繁,都可以保證在規定時間內可以執行一次執行函數。下面利用計算時間戳實現:

<input type="submit" id="btn" value="提交">
<script>
    var btn = document.getElementById('btn');
    // 點擊后觸發debounce()函數,第一個參數為真實要執行的函數,第二個參數為定時器延遲時間
    btn.addEventListener('click',throttle(submit,500));
    //真實要執行的函數
    function submit(e){
        console.log("提交成功!");
        console.log(this)
        // console.log(e);
    }
    //節流函數
    function throttle(fn,delay){
        //bef為上一次執行時間,初始值為0
        var bef = 0;
        return function (e){
            //獲取當前時間戳
            var now = new Date().getTime();
            //如果當前時間減去上次時間大於限制時間時才執行
            if(now - bef > delay){
                console.log(this);
                fn.call(this,arguments);
                bef = now;
            }
        }
    }
</script>

 運行后,狂點不停的話,每隔500毫秒才執行一次。

 也可以用定時器實現節流,如下:

<input type="submit" id="btn" value="提交">
<script>
    var btn = document.getElementById('btn');
    // 點擊后觸發debounce()函數,第一個參數為真實要執行的函數,第二個參數為定時器延遲時間
    btn.addEventListener('click',throttle(submit,500));
    //真實要執行的函數
    function submit(e){
        console.log("提交成功!");
        // console.log(this)
        console.log(e);
    }
    //節流函數
    function throttle(fn,delay){
        var flag = true;
        return function (e){
            if(flag){
                setTimeout(() => {
                    //到規定時間后執行函數,同時flag=true
                    fn(this,arguments);
                    flag = true;
                },delay);
            }
            //防止一直執行
            flag = false;
        };
    }

</script>

 

  總結

 最后我們也明白了防抖和節流的主要區別,那么他們各自適應的場景又有哪些呢?一般當我們提交表單時使用防抖,但在頁面的無限加載場景下,我們需要用戶在滾動頁面時,每隔一段時間發一次 ajax 請求,而不是在用戶停下滾動頁面操作時才去請求數據。這樣的場景,就適合用節流技術來實現。

 

 


 

參考文章:https://bbs.huaweicloud.com/blogs/297720?utm_source=cnblog&utm_medium=bbs-ex&utm_campaign=other&utm_content=content

 


免責聲明!

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



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