再學(xué)JS--事件節(jié)流

節(jié)流

節(jié)流:如果你持續(xù)觸發(fā)事件,每隔一段時(shí)間,只執(zhí)行一次事件

關(guān)于節(jié)流的實(shí)現(xiàn),有兩種主流的實(shí)現(xiàn)方式,一種是使用時(shí)間戳的方式,一種是設(shè)置定時(shí)器

使用時(shí)間戳

實(shí)現(xiàn)思路為:當(dāng)觸發(fā)條件的時(shí)候,我們?nèi)〕霎?dāng)前的時(shí)間戳,然后減去之前的時(shí)間戳(初始化為0),如果大于設(shè)定的時(shí)間周期,就執(zhí)行函數(shù),然后更新時(shí)間戳為當(dāng)前的時(shí)間戳,如果小于,則不執(zhí)行

function throttle(func, wait) {
    var context, args
    var previous = 0

    return function() {
        var now = +new Date()
        context = this
        args = arguments

        if(now - previous > wait) {
            func.apply(context, args)
            previous = now
        }
    }
}

使用定時(shí)器

實(shí)現(xiàn)思路為:當(dāng)觸發(fā)事件的時(shí)候,我們?cè)O(shè)置一個(gè)定時(shí)器,再次觸發(fā)事件的時(shí)候,如果定時(shí)器存在,就不執(zhí)行,直到定時(shí)器執(zhí)行,然后執(zhí)行函數(shù),清空定時(shí)器,再設(shè)置下一個(gè)定時(shí)器

function throttle(func, wait) {
    var timeout
    var context, args

    return function() {
        context = this
        args = arguments
        if(!timeout) {
            timeout = setTimeout(function() {
                timeout = null
                func.apply(context, args)
            }, wait)
        }
    }
}

比較兩種方法:

  1. 第一種事件會(huì)立即執(zhí)行,第二種事件會(huì)在n秒后第一次執(zhí)行
  2. 第一種事件停止觸發(fā)后沒(méi)有辦法再執(zhí)行事件,第二種事件停止觸發(fā)后依然會(huì)再執(zhí)行一次事件

雙劍合璧

鼠標(biāo)移入能立即執(zhí)行,停止觸發(fā)的時(shí)候還能再執(zhí)行一次

function throttle(func, wait) {
    var timeout, context, args, reslut
    var previous = 0

    var later = function() {
        previous = +new Date()
        timeout = null
        func.apply(context, args)
    }

    var throttled = function() {
        var now = +new Date()
        // 下次觸發(fā)func剩余時(shí)間
        var remaining = wait - (now - previous)
        context = this
        args = arguments
        // 如果沒(méi)有剩余時(shí)間了或者你改了系統(tǒng)時(shí)間
        if(remaining <=0 || remaining > wait) {
            if(timeout) {
                clearTimeout(timeout)
                timeout = null
            }
            previous = now
            func.apply(context, args)
        } else if(!timeout) {
            timeout = setTimeout(later, remaining)
        }
    }

    return throttled
}

優(yōu)化

我們可增加一個(gè)參數(shù)options來(lái)約定:

  1. leading:false表示禁用第一次執(zhí)行
  2. trailing:false表示禁用停止觸發(fā)的回調(diào)
function throttle(func, wait, options) {
    var timeout, context, args, reslut
    var previous = 0
    if(!options) options = {}

    var later = function() {
        previous = options.leading === false ? 0 : new Date().getTime()
        timeout = null
        func.apply(context, args)
        if(!timeout) context = args = null
    }

    var throttled = function() {
        var now = new Date().getTime()
        if(!previous && options.leading === false) previous = now
        // 下次觸發(fā)func剩余時(shí)間
        var remaining = wait - (now - previous)
        context = this
        args = arguments
        // 如果沒(méi)有剩余時(shí)間了或者你改了系統(tǒng)時(shí)間
        if(remaining <=0 || remaining > wait) {
            if(timeout) {
                clearTimeout(timeout)
                timeout = null
            }
            previous = now
            func.apply(context, args)
            if(!timeout) context = args = null
        } else if(!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining)
        }
    }

    // 取消功能
    throttled.cancel = function() {
        clearTimeout(timeout)
        previous = 0
        timeout = null
    }

    return throttled
}

注意

如果同時(shí)設(shè)置 leading:falsetrailing:false,比如當(dāng)你鼠標(biāo)移出的時(shí)候,因?yàn)閠railing設(shè)置為false,停止觸發(fā)的時(shí)候不會(huì)設(shè)置定時(shí)器,所以只要再過(guò)了設(shè)置的時(shí)間,再移入的話,就會(huì)立即執(zhí)行,就違反了leading:false,所以throttle只有三種用法:

throttle(func, 1000)
throttle(func, 1000, {leading:false})
throttle(func, 1000, {trailing:false})
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容