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

資訊專欄INFORMATION COLUMN

javaScript的Throttling(節(jié)流)和Debouncing(防抖)

Yujiaao / 1956人閱讀

摘要:節(jié)流和防抖都是用來提高用戶體驗(yàn),提高網(wǎng)站性能的手段,它們的技術(shù)手段都是強(qiáng)制事件處理函數(shù)在特定的事件段內(nèi)執(zhí)行。針對上面舉例的情況,其實(shí)運(yùn)用節(jié)流和防抖都可以做到,只是它們之間又有一定的區(qū)別節(jié)流節(jié)流是在一定的時(shí)間段內(nèi),函數(shù)最多可以被調(diào)用多少次。

“節(jié)流”和“防抖”都是用來提高用戶體驗(yàn),提高網(wǎng)站性能的手段,它們的技術(shù)手段都是“強(qiáng)制事件處理函數(shù)在特定的事件段內(nèi)執(zhí)行”。這樣解釋可能還是不夠直觀。舉兩個(gè)例子吧:

1: 比方說我們給document綁定了一個(gè)scroll的事件,scroll事件是每滑動一個(gè)px,scroll的處理函數(shù)就會被調(diào)用執(zhí)行,如果在你的處理函數(shù)里面恰巧做了一個(gè)很花時(shí)間或者很花空間的事情,比方說復(fù)雜的運(yùn)算啊,ajax請求啊,那這樣頁面就可能出現(xiàn)卡頓的情況。

2: 頁面上有個(gè)地址的輸入框,你希望根據(jù)客戶的輸入內(nèi)容,去幫客戶補(bǔ)全。假如說這個(gè)地址列表需要通過ajax請求來獲取,那我們一定是希望在客戶停止輸入了之后再去請求ajax然后來補(bǔ)全,而不是客戶一邊輸入就一直請求ajax。

針對上面舉例的情況,其實(shí)運(yùn)用節(jié)流和防抖都可以做到,只是它們之間又有一定的區(qū)別:

節(jié)流:節(jié)流是在一定的時(shí)間段內(nèi),函數(shù)最多可以被調(diào)用多少次。也可以理解為函數(shù)以一定的頻率被調(diào)用。
防抖:防抖是每次想要執(zhí)行這個(gè)函數(shù),都得事先等上一段時(shí)間。

語言總是這樣蒼白,直接來看代碼的實(shí)現(xiàn)吧。我們先來實(shí)現(xiàn)一個(gè)防抖:

//實(shí)現(xiàn)防抖函數(shù)
function debouncing(fn, waitTime){
    let timer = undefined;
    return function(){
        let context = this;
        let args = arguments;
        clearTimeout(timer);
        timer = setTimeout(function(){
            fn.apply(context, args);
        }, waitTime)
    }
}
//scroll事件的處理函數(shù)
function scrollHandler(event){
    console.log(new Date(event.timeStamp));
}
//document的scroll事件上使用防抖函數(shù)
document.addEventListener("scroll", debouncing(scrollHandler,100), false);

實(shí)現(xiàn)防抖函數(shù)的核心就是每次事件被觸發(fā)的時(shí)候,我們不是立即去調(diào)用相應(yīng)的handler,而是每一次都重新設(shè)置一個(gè)timeout,等待一段時(shí)間,然后再執(zhí)行我們的handler.

2: 現(xiàn)在來嘗試實(shí)現(xiàn)一個(gè)節(jié)流函數(shù):

function throttling(fn, intervalTime){
    let inInterval = false;
    return function(){
        let context = this;
        let args = arguments;
        if(!inInterval) {
            fn.apply(context, args);
            inInterval = true;
            setTimeout(function(){
                inInterval = false;
            }, intervalTime)
        }
        
    }
}

function scrollHandler(event){
    console.log(new Date(event.timeStamp));
}

document.addEventListener("scroll", throttling(scrollHandler,500), false);

節(jié)流的核心是管理一個(gè)布爾值開關(guān)變量(inInterval),在某種條件下切換它的true值和false值,而真正的事件處理函數(shù)只在這個(gè)開關(guān)變量的某一個(gè)值的時(shí)候才執(zhí)行,從而達(dá)到節(jié)流的目的。
節(jié)流函數(shù)它的實(shí)現(xiàn)有很多種,多種就在于控制這個(gè)開關(guān)變量的值的條件,會不一樣。在上面的例子里,我通過setTimeout的方式,間斷性的來改變inInterval的值。

現(xiàn)在來詳細(xì)分析一下上面的實(shí)現(xiàn):

1: 第一次scroll事件觸發(fā)的時(shí)候,scrollHandler就被立即執(zhí)行了,這個(gè)是我個(gè)人的一個(gè)考慮,希望對于第一次的事件觸發(fā)能馬上有一個(gè)回饋給客戶。

2: 但是當(dāng)?shù)谝淮螆?zhí)行完了之后,我們馬上把"inInterval=true", 假如這時(shí)候第二次scroll觸發(fā),代碼執(zhí)行到 if(!inInterval),因?yàn)闂l件表達(dá)式為false,所以scrollHandler不會被立即執(zhí)行。那可能之后的第三次,第四次。。。scroll事件觸發(fā)的時(shí)候,inInterval都是true,都不會執(zhí)行處理函數(shù)。

3: 我們之前在把inInterval設(shè)置為true之后,同時(shí)設(shè)置了一個(gè)timeout,在經(jīng)過一定的時(shí)間(intervalTime)之后,inInterval會被設(shè)置為false; 假如在這之后馬上又觸發(fā)了一次scroll事件,代碼走到if(!inInterval),條件為true,scrollHandler就可以被執(zhí)行了。

但是上面的代碼存在一個(gè)問題,假如我們最后一次的scroll事件,正好發(fā)生在這個(gè)循環(huán)時(shí)間內(nèi),那它就永遠(yuǎn)得不到執(zhí)行了。這個(gè)可能會是一個(gè)隱藏的bug, 比方說你在進(jìn)行一次拖拽事件,那目標(biāo)元素可能永遠(yuǎn)都拖不到目的地。
所以我們要改一下代碼,讓最后一次事件能被執(zhí)行:

function throttling(fn, intervalTime){
    let inInterval = false;
    let lastTimer = undefined;
    let timer = undefined;
    return function(){
        let context = this;
        let args = arguments;
        if(!inInterval) {
            clearTimeout(lastTimer); //這行代碼很重要
            fn.apply(context, args);
            inInterval = true;
            timer = setTimeout(function(){
                inInterval = false;
            }, intervalTime)
        }else{
            clearTimeout(lastTimer);
            lastTimer = setTimeout(function(){
                fn.apply(fn, args);
                inInterval = false;
            }, intervalTime);
        }
        
    }
}

function scrollHandler(event){
    console.log(new Date(event.timeStamp));
}

document.addEventListener("click", throttling(scrollHandler,1000), false);

上面的代碼,要特別解釋一下一下這一行代碼:clearTimeout(lastTimer); //這行代碼很重要

如果我們不加這行代碼的話,會出現(xiàn)先點(diǎn)擊的click事件反而后執(zhí)行的問題。比如;我們的intervalTime設(shè)置為10s, 然后我們分別在第0s, 第5秒,第12秒都進(jìn)行一次點(diǎn)擊,我們通過console.log(new Date(event.timeStamp)) 打印每一次事件發(fā)生時(shí)的時(shí)間, 我們會看到第5秒的那個(gè)click事件會比第12秒的那個(gè)click后輸出,這就說明這里有問題。

所以我們要在if(!inInterval){}里面把lastTimer給清掉,也就是通過clearTimeout(lastTimer); 這行代碼。

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

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

相關(guān)文章

  • 理解節(jié)流防抖

    摘要:節(jié)流節(jié)流限制了一個(gè)函數(shù)可以在短時(shí)間內(nèi)被調(diào)用的次數(shù)。更新防抖防抖確保了一個(gè)函數(shù)只有在一個(gè)固定時(shí)間段內(nèi)沒有被調(diào)用過后,才會再次被調(diào)用。再換句話說防抖會等待事件不再高頻發(fā)生,再觸發(fā)。這個(gè)網(wǎng)站很好的可視化了節(jié)流與防抖。 節(jié)流 Throttling 節(jié)流限制了一個(gè)函數(shù)可以在短時(shí)間內(nèi)被調(diào)用的次數(shù)??梢赃@樣形容:在一毫秒內(nèi)最多執(zhí)行此函數(shù) 1 次。 Throttling enforces a maxi...

    glumes 評論0 收藏0
  • 高級函數(shù)技巧-函數(shù)防抖節(jié)流

    摘要:封裝方法也比較簡單,書中對此問題也進(jìn)行了處理使用定時(shí)器,讓函數(shù)延遲秒后執(zhí)行,在此秒內(nèi),然后函數(shù)再次被調(diào)用,則刪除上次的定時(shí)器,取消上次調(diào)用的隊(duì)列任務(wù),重新設(shè)置定時(shí)器。 在實(shí)際開發(fā)中,函數(shù)一定是最實(shí)用最頻繁的一部分,無論是以函數(shù)為核心的函數(shù)式編程,還是更多人選擇的面向?qū)ο笫降木幊?,都會有函?shù)的身影,所以對函數(shù)進(jìn)行深入的研究是非常有必要的。 函數(shù)節(jié)流 比較直白的說,函數(shù)節(jié)流就是強(qiáng)制規(guī)定一...

    whinc 評論0 收藏0
  • Javascript 面試中經(jīng)常被問到三個(gè)問題!

    摘要:相反,在討論時(shí),面試中通常會提到三件事。而認(rèn)為最后一個(gè)參賽者說了算,只要還能吃的,就重新設(shè)定新的定時(shí)器。試想,如果用戶的操作十分頻繁他每次都不等設(shè)置的時(shí)間結(jié)束就進(jìn)行下一次操作,于是每次都為該用戶重新生成定時(shí)器,回調(diào)函數(shù)被延遲了不計(jì)其數(shù)次。本文不是討論最新的 JavaScript 庫、常見的開發(fā)實(shí)踐或任何新的 ES6 函數(shù)。相反,在討論 JavaScript 時(shí),面試中通常會提到三件事。我自己...

    chnmagnus 評論0 收藏0
  • 3個(gè)經(jīng)常被問到 JavaScript 面試題

    摘要:更高效的解決方案是將一個(gè)事件偵聽器實(shí)際綁定到父容器上,然后在實(shí)際單擊時(shí)可以訪問每個(gè)確切元素。如果將事件偵聽器綁定到窗口滾動事件上,并且用戶快速滾動頁面,事件很可能會在短時(shí)間多次觸發(fā)。 原文鏈接 問題 #1: 事件委托 事件委托,也叫事件委派,事件代理。 當(dāng)構(gòu)建應(yīng)用程序時(shí),有時(shí)需要將事件監(jiān)聽器綁定到頁面上的某些元素上,以便在用戶與元素交互時(shí)執(zhí)行某些操作。 假設(shè)我們現(xiàn)在有一個(gè)無序列表: ...

    Galence 評論0 收藏0
  • [譯]通過實(shí)例講解DebouncingThrotting(防抖節(jié)流)

    摘要:譯通過實(shí)例講解和防抖與節(jié)流源碼中推薦的文章,為了學(xué)習(xí)英語,翻譯了一下原文鏈接作者本文來自一位倫敦前端工程師的技術(shù)投稿。首次或立即你可能發(fā)現(xiàn)防抖事件在等待觸發(fā)事件執(zhí)行,直到事件都結(jié)束后它才執(zhí)行。 [譯]通過實(shí)例講解Debouncing和Throtting(防抖與節(jié)流) lodash源碼中推薦的文章,為了學(xué)習(xí)(英語),翻譯了一下~ 原文鏈接 作者:DAVID CORBACHO 本文來自一位...

    Jenny_Tong 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<