成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript專題之跟著 underscore 學(xué)節(jié)流

JerryC / 2709人閱讀

摘要:關(guān)于節(jié)流的實(shí)現(xiàn),有兩種主流的實(shí)現(xiàn)方式,一種是使用時(shí)間戳,一種是設(shè)置定時(shí)器。當(dāng)觸發(fā)事件的時(shí)候,我們?cè)O(shè)置一個(gè)定時(shí)器,再觸發(fā)事件的時(shí)候,如果定時(shí)器存在,就不執(zhí)行,直到定時(shí)器執(zhí)行,然后執(zhí)行函數(shù),清空定時(shí)器,這樣就可以設(shè)置下個(gè)定時(shí)器。

JavaScript 專題系列第二篇,講解節(jié)流,帶你從零實(shí)現(xiàn)一個(gè) underscore 的 throttle 函數(shù)

前言

在《JavaScript專題之跟著underscore學(xué)防抖》中,我們了解了為什么要限制事件的頻繁觸發(fā),以及如何做限制:

debounce 防抖

throttle 節(jié)流

今天重點(diǎn)講講節(jié)流的實(shí)現(xiàn)。

節(jié)流

節(jié)流的原理很簡(jiǎn)單:

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

根據(jù)首次是否執(zhí)行以及結(jié)束后是否執(zhí)行,效果有所不同,實(shí)現(xiàn)的方式也有所不同。
我們用 leading 代表首次是否執(zhí)行,trailing 代表結(jié)束后是否再執(zhí)行一次。

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

使用時(shí)間戳

讓我們來(lái)看第一種方法:使用時(shí)間戳,當(dāng)觸發(fā)事件的時(shí)候,我們?nèi)〕霎?dāng)前的時(shí)間戳,然后減去之前的時(shí)間戳(最一開始值設(shè)為 0 ),如果大于設(shè)置的時(shí)間周期,就執(zhí)行函數(shù),然后更新時(shí)間戳為當(dāng)前的時(shí)間戳,如果小于,就不執(zhí)行。

看了這個(gè)表述,是不是感覺(jué)已經(jīng)可以寫出代碼了…… 讓我們來(lái)寫第一版的代碼:

// 第一版
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;
        }
    }
}

例子依然是用講 debounce 中的例子,如果你要使用:

container.onmousemove = throttle(getUserAction, 1000);

效果演示如下:

我們可以看到:當(dāng)鼠標(biāo)移入的時(shí)候,事件立刻執(zhí)行,每過(guò) 1s 會(huì)執(zhí)行一次,如果在 4.2s 停止觸發(fā),以后不會(huì)再執(zhí)行事件。

使用定時(shí)器

接下來(lái),我們講講第二種實(shí)現(xiàn)方式,使用定時(shí)器。

當(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 previous = 0;

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

    }
}

為了讓效果更加明顯,我們?cè)O(shè)置 wait 的時(shí)間為 3s,效果演示如下:

我們可以看到:當(dāng)鼠標(biāo)移入的時(shí)候,事件不會(huì)立刻執(zhí)行,晃了 3s 后終于執(zhí)行了一次,此后每 3s 執(zhí)行一次,當(dāng)數(shù)字顯示為 3 的時(shí)候,立刻移出鼠標(biāo),相當(dāng)于大約 9.2s 的時(shí)候停止觸發(fā),但是依然會(huì)在第 12s 的時(shí)候執(zhí)行一次事件。

所以比較兩個(gè)方法:

第一種事件會(huì)立刻執(zhí)行,第二種事件會(huì)在 n 秒后第一次執(zhí)行

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

雙劍合璧

那我們想要一個(gè)什么樣的呢?

有人就說(shuō)了:我想要一個(gè)有頭有尾的!就是鼠標(biāo)移入能立刻執(zhí)行,停止觸發(fā)的時(shí)候還能再執(zhí)行一次!

所以我們綜合兩者的優(yōu)勢(shì),然后雙劍合璧,寫一版代碼:

// 第三版
function throttle(func, wait) {
    var timeout, context, args, result;
    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;
}

效果演示如下:

我們可以看到:鼠標(biāo)移入,事件立刻執(zhí)行,晃了 3s,事件再一次執(zhí)行,當(dāng)數(shù)字變成 3 的時(shí)候,也就是 6s 后,我們立刻移出鼠標(biāo),停止觸發(fā)事件,9s 的時(shí)候,依然會(huì)再執(zhí)行一次事件。

優(yōu)化

但是我有時(shí)也希望無(wú)頭有尾,或者有頭無(wú)尾,這個(gè)咋辦?

那我們?cè)O(shè)置個(gè) options 作為第三個(gè)參數(shù),然后根據(jù)傳的值判斷到底哪種效果,我們約定:

leading:false 表示禁用第一次執(zhí)行
trailing: false 表示禁用停止觸發(fā)的回調(diào)

我們來(lái)改一下代碼:

// 第四版
function throttle(func, wait, options) {
    var timeout, context, args, result;
    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;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        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);
        }
    };
    return throttled;
}
取消

在 debounce 的實(shí)現(xiàn)中,我們加了一個(gè) cancel 方法,throttle 我們也加個(gè) cancel 方法:

// 第五版 非完整代碼,完整代碼請(qǐng)查看最后的演示代碼鏈接
...
throttled.cancel = function() {
    clearTimeout(timeout);
    previous = 0;
    timeout = null;
}
...
注意

我們要注意 underscore 的實(shí)現(xiàn)中有這樣一個(gè)問(wèn)題:

那就是 leading:falsetrailing: false 不能同時(shí)設(shè)置。

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

container.onmousemove = throttle(getUserAction, 1000);
container.onmousemove = throttle(getUserAction, 1000, {
    leading: false
});
container.onmousemove = throttle(getUserAction, 1000, {
    trailing: false
});

至此我們已經(jīng)完整實(shí)現(xiàn)了一個(gè) underscore 中的 throttle 函數(shù),恭喜,撒花!

演示代碼

相關(guān)的代碼可以在 Github 博客倉(cāng)庫(kù) 中找到

專題系列

JavaScript專題系列目錄地址:https://github.com/mqyqingfeng/Blog。

JavaScript專題系列預(yù)計(jì)寫二十篇左右,主要研究日常開發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖、節(jié)流、去重、類型判斷、拷貝、最值、扁平、柯里、遞歸、亂序、排序等,特點(diǎn)是研(chao)究(xi) underscore 和 jQuery 的實(shí)現(xiàn)方式。

如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤?,?qǐng)務(wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎 star,對(duì)作者也是一種鼓勵(lì)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/83539.html

相關(guān)文章

  • JavaScript專題系列20篇正式完結(jié)!

    摘要:寫在前面專題系列是我寫的第二個(gè)系列,第一個(gè)系列是深入系列。專題系列自月日發(fā)布第一篇文章,到月日發(fā)布最后一篇,感謝各位朋友的收藏點(diǎn)贊,鼓勵(lì)指正。 寫在前面 JavaScript 專題系列是我寫的第二個(gè)系列,第一個(gè)系列是 JavaScript 深入系列。 JavaScript 專題系列共計(jì) 20 篇,主要研究日常開發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖、節(jié)流、去重、類型判斷、拷貝、最值、扁平、柯里...

    sixleaves 評(píng)論0 收藏0
  • JavaScript專題系列文章

    摘要:專題系列共計(jì)篇,主要研究日常開發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖節(jié)流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點(diǎn)是研究專題之函數(shù)組合專題系列第十六篇,講解函數(shù)組合,并且使用柯里化和函數(shù)組合實(shí)現(xiàn)模式需求我們需要寫一個(gè)函數(shù),輸入,返回。 JavaScript 專題之從零實(shí)現(xiàn) jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實(shí)現(xiàn)一個(gè) jQuery 的 ext...

    Maxiye 評(píng)論0 收藏0
  • 20190726-前端筆記-防抖和節(jié)流

    摘要:定義定時(shí)器清空定時(shí)器重置定時(shí)器防抖流程觸發(fā)觸發(fā)定義一個(gè)定時(shí)器,返回執(zhí)行內(nèi)容為清除當(dāng)前定時(shí)器,定義執(zhí)行內(nèi)容。 防抖 為了避免一些監(jiān)聽事件為在自己預(yù)料的情況,頻繁觸發(fā)。or 在某些監(jiān)聽命令會(huì)頻繁觸發(fā)事件比如resize、mousemove等等 未防抖 示例 var count = 0, Elem = doc.getElementById(con) ...

    Thanatos 評(píng)論0 收藏0
  • 20190726-前端筆記-防抖和節(jié)流

    摘要:定義定時(shí)器清空定時(shí)器重置定時(shí)器防抖流程觸發(fā)觸發(fā)定義一個(gè)定時(shí)器,返回執(zhí)行內(nèi)容為清除當(dāng)前定時(shí)器,定義執(zhí)行內(nèi)容。 防抖 為了避免一些監(jiān)聽事件為在自己預(yù)料的情況,頻繁觸發(fā)。or 在某些監(jiān)聽命令會(huì)頻繁觸發(fā)事件比如resize、mousemove等等 未防抖 示例 var count = 0, Elem = doc.getElementById(con) ...

    JasinYip 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<