成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

【譯】通過例子解釋 Debounce 和 Throttle

LeoHsiun / 2438人閱讀

摘要:舉例舉例通過拖拽瀏覽器窗口,可以觸發(fā)很多次事件。不支持,所以不能在服務(wù)端用于文件系統(tǒng)事件??偨Y(jié)將一系列迅速觸發(fā)的事件例如敲擊鍵盤合并成一個多帶帶的事件。確保一個持續(xù)的操作流以每毫秒執(zhí)行一次的速度執(zhí)行。

DebounceThrottle 是兩個很相似但是又不同的技術(shù),都可以控制一個函數(shù)在一段時間內(nèi)執(zhí)行的次數(shù)。

當(dāng)我們在操作 DOM 事件的時候,為函數(shù)添加 debounce 或者 throttle 就會尤為有用。為什么?因為我們在事件和函數(shù)執(zhí)行之間加了一個我們自己的控制層。記住,我們是不去控制這些 DOM 事件觸發(fā)的頻率的,因為這個可能會有變化。

下面我們以滾動事件舉例:

當(dāng)使用觸控板、鼠標(biāo)滾輪,或者直接拽動滾動條,每秒都可以輕易觸發(fā)至少30次事件,而且在觸屏的移動端,甚至?xí)_(dá)到每秒100次,面對這樣高的執(zhí)行頻率,你的滾動事件處理程序能否很好地應(yīng)對?

在2011年,Twitter 網(wǎng)站提出了一個 issue:當(dāng)向下滾動 Twitter 信息流的時候,整個頁面的響應(yīng)速度都會變慢。 John Resig 基于該問題發(fā)表了一篇博客,文中指出,直接在 scroll 事件里掛載一些計算量大的函數(shù)是件多么不明智的行為。

John 當(dāng)時提出的解決方案是在 onScroll event 的外部設(shè)置一個每 250ms 執(zhí)行一次的循環(huán)。這樣處理程序就與事件解耦了。使用這樣一個簡單的技術(shù)就可以避免破壞用戶體驗。

::: tip 譯者注

文中的核心代碼如下

var outerPane = $details.find(".details-pane-outer"),
    didScroll = false;

$(window).scroll(function() {
    didScroll = true;
});

setInterval(function() {
    if ( didScroll ) {
        didScroll = false;
        // Check your page position and then
        // Load in more results
    }
}, 250);

:::

如今,處理事件的方式稍微復(fù)雜了一些。下面我們結(jié)合用例,一一介紹 Debounce、 Throttle 和requestAnimationFrame。

Debounce

Debounce 允許我們將多個連續(xù)的調(diào)用合并成一個。

想象一個進電梯的場景,你走進了電梯,門剛要關(guān)上,這時另一個人想要進來,于是電梯沒有移動樓層(處理函數(shù)),而是將門打開讓那個人進來。這時又有一個人要進來,就又會上演剛才那一幕。也就是說,電梯延遲了它的函數(shù)(移動樓層)執(zhí)行,但是優(yōu)化了資源。

在下面的例子中,嘗試快速點擊按鈕或者在上面滑動:

你可以看到連續(xù)快速事件是怎樣被一個多帶帶的 debounce 事件所替代的。但是如果事件觸發(fā)時間間隔較長,就不會發(fā)生 debounce。

Leading 邊緣 (或者 "immediate")

在上面的例子中,你會發(fā)現(xiàn) debounce 事件會等到快速事件停止發(fā)生后才會觸發(fā)函數(shù)執(zhí)行。為什么不在每次一開始就立即觸發(fā)函數(shù)執(zhí)行呢,這樣它的表現(xiàn)就和原始的沒有去抖的處理器一樣了。直到快速調(diào)用出現(xiàn)停頓的時候,才會再次觸發(fā)。

下面是使用 leading 標(biāo)識符的例子:

在 underscore.js 中,該選項叫作 immediate ,而不是 leading。

自己試一下:

Debounce 的實現(xiàn)

Debounce 的概念和實現(xiàn)最早是由 John Hann 在2009年提出來的。

不久之后,Ben Alman 就寫了一個 jQuery 插件(現(xiàn)在已經(jīng)不再維護了),一年之后 Jeremy Ashkenas 把它添加進了 underscore.js。再后來被添加進 Lodash。

這三個實現(xiàn)在內(nèi)部有一點不同,但是接口幾乎是相同的。

曾經(jīng)有一段時間,underscore 采取了 Lodash 里面的 debounce/throttle 實現(xiàn),但是后來我在2013年發(fā)現(xiàn)了 _.debounce 函數(shù)的一個 bug。從那時起,這兩種實現(xiàn)就出現(xiàn)分化了。

Lodash 為 _.debounce_.throttle 添加了更多的特性。最初的 immediate 標(biāo)識符被 leadingtrailing 所替代。你可以選擇一個選項,也可以兩個都要。默認(rèn)情況下 trailing 是被開啟的。

新的 maxWait 選項(目前只存在于Lodash)在本文中沒有提及,但是它也是一個很有用的選項。實際上,throttle 函數(shù)就是使用 _.debounce 帶著 maxWait 的選項來定義的,你可以在這里查看源碼。

Debounce 舉例
Resize 舉例

通過拖拽瀏覽器窗口,可以觸發(fā)很多次 resize 事件。

例子如下:


可以看到,我們在 resize 事件上使用的是默認(rèn)的 trailing 選項,因為我們只需要關(guān)心用戶停止調(diào)整瀏覽器后的最終結(jié)果就可以了。

敲擊鍵盤,通過 Ajax 請求自動填充表單

為什么要在用戶還在輸入的時候每隔 50ms 就發(fā)送一次 Ajax請求?_.debounce 可以幫助我們避免額外的開銷,只有當(dāng)用戶停止輸入了再發(fā)送請求。

這里沒有必要設(shè)置 leading,我們是想要等到最后一個字符輸入完再執(zhí)行函數(shù)的。


還有一個類似的使用場景就是表單校驗,當(dāng)用戶輸入完再進行校驗、提示信息等。

如何使用 debounce 和 throttle,以及常見問題

說了這么多,你可能已經(jīng)想自己來寫 debounce/throttle 函數(shù)了,或者是從網(wǎng)上隨便一篇博客上拷貝一份下來。但是我給你的建議是直接使用 underscore 或者 Lodash。 如果你只是需要 _.debounce_.throttle 函數(shù),可以使用 Lodash custom builder 來輸出一個自定義的壓縮后為 2KB 的庫??梢允褂孟铝忻顏磉M行構(gòu)建:

npm i -g lodash-cli
lodash include = debounce, throttle

也就是說,最好是使用模塊化的形式,通過 webpack/browserify/rollup 來引用,如 lodash/throttlelodash/debouncelodash.throttlelodash.debounce 。

使用 _.debounce 函數(shù)的一個常見錯誤就是多次調(diào)用它:

// 錯誤
$(window).on("scroll", function() {
   _.debounce(doSomething, 300); 
});

// 正確
$(window).on("scroll", _.debounce(doSomething, 200));

為 debounced 函數(shù)創(chuàng)建一個變量可以讓我們調(diào)用私有函數(shù) debounced_version.cancel(),如果有需要,lodash 和 underscore.js 都可以供你使用。

var debounced_version = _.debounce(doSomething, 200);
$(window).on("scroll", debounced_version);

// 如果你需要的話
debounced_version.cancel();
Throttle

使用 _.throttle 則不允許函數(shù)每 X 毫秒的執(zhí)行次數(shù)超過一次。

Throttle 和 debounce 最主要的區(qū)別就是 throttle 保證函數(shù)每 X 毫秒至少執(zhí)行一次。

和 debounce 一樣, throttle 也用在了 Ben 的插件、underscore.js 和 lodash里面。

Throttling 舉例
無限滾動

這是一個非常常見的例子。用戶在一個無限滾動的頁面里向下滾動,你需要知道當(dāng)前滾動的位置距離底部還有多遠(yuǎn),如果接近底部了,我們就得通過 Ajax 請求獲取更多的內(nèi)容,將其添加到頁面里。

此時我們之前的 _.debounce 就派不上作用了。使用 debounce 只有當(dāng)用戶停止?jié)L動時才能觸發(fā),而我們需要的是在用戶滾動到底部之前就開始獲取內(nèi)容。

使用 _.throttle 就能確保實時檢查距離底部還有多遠(yuǎn)。

requestAnimationFrame (rAF)

requestAnimationFrame 是另一種限制函數(shù)執(zhí)行速度的方法。

它可以被看做 _.throttle(dosomething, 16)。但它有著更高的保真度,因為它是瀏覽器的原生 API,有著更好的精度。

我們可以使用 rAF API,作為 throttle 函數(shù)的替代,考慮下面的優(yōu)缺點:

優(yōu)點

目標(biāo)是 60fps(每幀 16ms),但是會在瀏覽器內(nèi)部決定如何安排渲染的最佳時機。

非常簡單,而且是標(biāo)準(zhǔn) API,在未來也不會改變。更少的維護成本。

缺點

rAFs 的開始/取消由我們自己來管理,而不像 .debounce.throttle 是在內(nèi)部管理的。

如果瀏覽器的 tab 頁面不活躍了,它就不會再執(zhí)行。

雖然所有的現(xiàn)代瀏覽器都提供了 rAF, 但是 IE9、Opera Mini 和一些老的安卓版本還不支持。如果需要,現(xiàn)在還是要使用 polyfill 。

Node.js 不支持 rAF,所以不能在服務(wù)端用于 throttle 文件系統(tǒng)事件。

根據(jù)經(jīng)驗,如果你的 JavaScript 函數(shù)是在繪制或者直接改變屬性,所有涉及到元素位置重新計算的,我會建議使用 requestAnimationFrame,

如果是處理 Ajax 請求,或者決定是否添加/刪除某個 class(可能會觸發(fā)一個 CSS 動畫),我會考慮 _.debounce_.throttle,這里可以設(shè)置更低一些的執(zhí)行速度(例如 200ms,而不是16ms)。

這時你可能會想,為什不把 rAF 集成到 underscore 或 lodash 里呢,那他倆都是拒絕的,因為這只是一個特殊的使用場景,而且已經(jīng)足夠簡單,可以被直接調(diào)用。

rAF 舉例

受這篇文章的啟發(fā),在這里我會舉一個滾動的例子,在這篇文章中有每個步驟的邏輯解釋。

我做了一個對比實驗,一邊是 rAF,一邊是 16ms 間隔的 _.throttle。它們性能很相似,但是 rAF 可能會在更復(fù)雜的場景下性能更高一些。

See the Pen Scroll comparison requestAnimationFrame vs throttle


還有一個更高級的例子,在 headroom.js 中,邏輯被解耦了,并且包裹在了對象中。

總結(jié)

使用 debounce、throttle 和 requestAnimationFrame 來優(yōu)化你的事件處理程序。每種技術(shù)都有些許的不同,但是三個都是很有用的,而且能夠互補。

總結(jié):

debounce:將一系列迅速觸發(fā)的事件(例如敲擊鍵盤)合并成一個多帶帶的事件。

throttle:確保一個持續(xù)的操作流以每 X 毫秒執(zhí)行一次的速度執(zhí)行。例如每 200ms 檢查一下滾動條的位置來觸發(fā)某個 CSS 動畫。

requestAnimationFrame:throttle的一個替代品。適用于需要計算元素在屏幕上的位置和渲染的時候,能夠保證動畫或者變化的平滑性。注意:IE9 不支持。

原文鏈接:https://css-tricks.com/deboun...

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

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/97157.html

相關(guān)文章

  • []通過實例講解DebouncingThrotting(防抖與節(jié)流)

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

    Jenny_Tong 評論0 收藏0
  • 淺談throttle以及debounce的原理實現(xiàn)

    摘要:淺談以及的原理和實現(xiàn)背景日常開發(fā)中我們經(jīng)常會遇到一些需要節(jié)流調(diào)用或者壓縮調(diào)用次數(shù)的情況例如之前我在完成一個需求的時候就遇到了因為后端并發(fā)問題導(dǎo)致收到多條信息從而導(dǎo)致函數(shù)被重復(fù)調(diào)用的情況當(dāng)時的做法是通過對函數(shù)的調(diào)用進行注冊遇到多次調(diào)用的時候清 淺談throttle以及debounce的原理和實現(xiàn) 背景 日常開發(fā)中,我們經(jīng)常會遇到一些需要節(jié)流調(diào)用,或者壓縮調(diào)用次數(shù)的情況,例如之前我在完成...

    jsbintask 評論0 收藏0
  • 【源碼分析】給你幾個鬧鐘,或許用 10 分鐘就能寫出 lodash 中的 debounce &

    摘要:最簡單的案例以最簡單的情景為例在某一時刻點只調(diào)用一次函數(shù),那么將在時間后才會真正觸發(fā)函數(shù)。后續(xù)我們會逐漸增加黑色鬧鐘出現(xiàn)的復(fù)雜度,不斷去分析紅色鬧鐘的位置。 序 相比網(wǎng)上教程中的 debounce 函數(shù),lodash 中的 debounce 功能更為強大,相應(yīng)的理解起來更為復(fù)雜; 解讀源碼一般都是直接拿官方源碼來解讀,不過這次我們采用另外的方式:從最簡單的場景開始寫代碼,然后慢慢往源碼...

    余學(xué)文 評論0 收藏0
  • throttledebounce的區(qū)別

    摘要:自己嘗試一下年在的文章中第一次看到的實現(xiàn)方法。這三種實現(xiàn)方法內(nèi)部不同,但是接口幾乎一致。如你所見,我們使用了參數(shù),因為我們只對用戶停止改變?yōu)g覽器大小時最后一次事件感興趣。 前幾天看到一篇文章,我的公眾號里也分享了《一次發(fā)現(xiàn)underscore源碼bug的經(jīng)歷以及對學(xué)術(shù)界拿來主義的思考》具體文章詳見,微信公眾號:showImg(https://segmentfault.com/img/b...

    Pluser 評論0 收藏0
  • Debounce vs Throttle

    摘要:那么還有最后一個問題,那我之前設(shè)置的定時器怎么辦呢定時器執(zhí)行的是這個函數(shù),而這個函數(shù)又會通過進行一次判斷。 我們在處理事件的時候,有些事件由于觸發(fā)太頻繁,而每次事件都處理的話,會消耗太多資源,導(dǎo)致瀏覽器崩潰。最常見的是我們在移動端實現(xiàn)無限加載的時候,移動端本來滾動就不是很靈敏,如果每次滾動都處理的話,界面就直接卡死了。 因此,我們通常會選擇,不立即處理事件,而是在觸發(fā)一定次數(shù)或一定時間...

    xcold 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<