天天看點

函數節流和函數防抖函數節流和函數防抖

函數節流和函數防抖

函數節流概念: 函數預先設定一個執行周期,當調用動作的時刻大于等于執行周期則執行該動作,然後進入下一個新周期

比如在做網頁的時候有個需求,就是浏覽器視窗改變的時候需要改一些頁面元素大小,于是乎很自然的想到了window的resize事件

<script>

    var n = 0;
    function resizeHandler () {
        console.log(n++);
    }
    window.onresize = resizeHandler
</script>
           

效果随着視窗大小改變不停列印n的值

使用函數節流

<script>
    var n = 0;
    function resizeHandler () {
        console.log(n++)
    }
    function throttle (method, delay) {
        var timer = null;
        return function () {
            var context = this;
            var args = arguments;
            clearTimeout(timer);
            timer = setTimeout(() => {
                method.apply(context, args)
            }, delay);
        }
    }
    window.onresize = throttle(resizeHandler, 500);//因為傳回函數句柄,不用包裝函數了
</script>
           

視窗大小改變,不斷列印n的值,但不要一直列印,500ms内如果沒有繼續拖動,則列印值

對于函數節流,有如下幾個場景:

  • 遊戲中的重新整理率
  • DOM元素拖拽
  • Canvas畫筆功能

函數防抖:函數執行過一次後,在等待某時間段内不能再次執行;在等待時間内觸發此函數,則重新計算等待時間

<script>
    var n = 0;
    function debounce (method, wait, flag) {
        var timer = null;
        var context, args, result, timestamp;
        var later = function () {
            var oDate = new Date();
            var last = oDate.getTime() - timestamp; // 計算第一次時間戳與目前時間戳的內插補點。
            if (last < wait && last >= 0 ) { // 在等待時間内觸發此函數,重新計時。
                timer = setTimeout(later, wait - last);
            } else {
                timer = null;
                if (!flag) { // 限制flag 為true時,執行回調函數。
                    result = method.apply(context, args);
                    if (!timer) {
                        context = args = null
                    }
                }
            }
        }

        return function () {
            var oDate = new Date();
            var callNow = flag && !timer; // 代表第一次調用立即執行。

            timestamp = oDate.getTime(); // 記錄下目前時間戳
            context = this;
            args = arguments;
            if (!timer) { // 第一次觸發時,timer為空,進入此分支
                timer = setTimeout(later, wait);
            }
            if (callNow) { // 第一次觸發且flag為true,進入此分支
                result = method.apply(context, args);
                context = args = null
            }
            return result;
        }
    }
    window.onscroll = debounce (function () {
        console.log(1)
    }, 500, false)
</script>
           

此次封裝支援兩種形式:

flag為true時,連續事件觸發時,隻會在第一次觸發的時候執行回調。

flag為false時,連續事件觸發時,隻會在最後一次觸發的時候執行回調。

對于函數防抖,有以下幾種應用場景:

  • 給按鈕加函數防抖防止表單多次送出。
  • 對于輸入框連續輸入進行AJAX驗證時,用函數防抖能有效減少請求次數。
  • 判斷scroll是否滑到底部,滾動事件+函數防抖

    總的來說,适合多次事件一次響應的情況

歡迎大家點贊和評論,如有不足之處請大神指出,剛入門,請多多指教。

繼續閱讀