1. 程式人生 > >js的節流和防抖

js的節流和防抖

1,節流

  節流就是對連續的函式觸發,在設定的間隔時間段內,只讓其執行一次。

  先來看看js高階程式設計3裡面節流的程式碼

function throttle (method, context, wait) {
    clearTimeout(method.tId)
     method.tId = setTimeout(function () {
         method.call(context)
     }, wait)
}

       當函式連續執行的時候,如果之前的定時器還沒執行,就把它清除了,再從新設定一個新的定時器。

  我們可以對這個進行改進

function throttle (fn, wait) {
let timeout;
let prevTime = 0;
return (...args) => { //返回一個函式
let now = new Date;
let remaining = wait - (now - prevTime) // 下一次執行的時間,
if (remaining <=0 || remaining > wait) { // 如果下一次的時間小於等於0,立刻執行一次函式,並把時間戳改為當前的時間。
clearTimeout(timeout)
timeout = null
prevTime = now
fn(args)
} else if (!timeout) { // 如果當前沒有定時器 那麼就新加一個定時器。
timeout = setTimeout(() => {
timeout = null;
prevTime = new Date;
fn(args)
}, remaining)
}
}
}

  第一次執行: timeout為undefined, prevTime為0     remaining為負數,走if的第一個,立即執行了函式並將下次時間改成當前時間

  第二次執行: 下一次時間為正,定時器還是為undefined,走if的第二個,設定定時器

     下一次執行(不超過wait時間內) :  remaining大於0,定時器為true,所以直接跳出

  

    understore裡面的節流考慮了兩個高階的配置:  是否在第一次觸發的時候就執行函式 和  最後一次的定時器觸發的執行函式。還提供了節流的取消函式。

function throttle(fn, wait, option = {}) {
        let timeout;
        let prevTime = 0
        let throttled = (...args) => {
            let now = new Date;
            if (!prevTime && option.leading === false) prevTime = now;
            let remaining = wait - (now - prevTime);
            if (remaining <= 0 || remaining > wait) {
                if (timeout) {
                    clearTimeout(timeout)
                    timeout = null;
                }
                prevTime = now
                fn(args)
            } else if (!timeout && option.trailing !== false) {
                timeout = setTimeout(() => {
                    prevTime = option.leading === false ? 0 : new Date;
                    fn(args)
                })
            }
        }
        throttled.cancel = () => {
            clearTimeout(timeout);
            prevTime = 0;
            timeout = null;
        }
        return throttled
}

  除了加了兩個配置項和取消函式,別的基本都是一樣的。

  需要注意的是,首次不執行和最後不執行這兩個不能同時配置,只能配置一個。

 

2,防抖

  其實我感覺防抖和節流差別不大,主要的差別在於: 在wait的時間內,反覆觸發函式的話,節流不會理會這些,而防抖的話,只要你觸發了,他就會清除之前的定時器,從新設定一個定時器。

  比如說坐電梯,如果是節流的話,電梯等待時間為5S,從第一個人進電梯開始算,到5S後他就會關門執行。

           如果是防抖的話,電梯等待時間為5S,在這5S之內,如果有人進電梯,他就會重新計時,只有在5S中沒有人進電梯了,電梯才關門執行。

function debounce (fn, wait) {
let timeout;
return (...args) => {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
fn(args)
}, wait)
}
}

  返回一個函式, 先清除之前的定時器,然後再新加定時器。

 

  underscore裡面的防抖添加了一個高階配置,是否立即執行一次函式。

function debounce(fn, wait, immediate) {
       let timeout;
       return (...args) => {
           let callNow = immediate && !timeout;
           if (timeout) clearTimeout(timeout);
           timeout = setTimeout(() => {
               timeout = null;
               if (!immediate) fn(args)
           }, wait)
           if (callNow) fn(args)
       }
}

  這裡添加了immediate這個配置項,如果為true的話,那麼觸發第一次的時候就執行了要執行的函式,定時器裡面不執行。