摘要:如果我們的回調(diào)函數(shù)較為復(fù)雜,頁面的性能就會變差。而可以保證穩(wěn)定的時間間隔執(zhí)行一次回調(diào)函數(shù)。但需要弄清楚的是,無論是還是,控制的都是回調(diào)函數(shù)的執(zhí)行,而不是事件的監(jiān)聽。
前言
假設(shè)現(xiàn)在有個需求:監(jiān)聽滑動事件,并執(zhí)行回調(diào)。
當(dāng)你用觸摸板或者鼠標(biāo)滑動頁面時,每秒鐘大概會觸發(fā)幾十次scroll事件,而當(dāng)你在手機(jī)
等移動終端上滑動頁面時,每秒就會觸發(fā)一百次scroll事件。如果我們的回調(diào)函數(shù)較為復(fù)雜,頁面的性能就會變差。
解決問題的兩種工具:debounce、throttle,它們有些類似,比如作用都是控制目標(biāo)函數(shù)在一段時間內(nèi)執(zhí)行的次數(shù);但更多的是不同:debounce使得在前后兩次事件間隔不超過一定時間的情況下,無論觸發(fā)多少次事件都只會執(zhí)行一次回調(diào)函數(shù)。而throttle可以保證穩(wěn)定的時間間隔執(zhí)行一次回調(diào)函數(shù)。但需要弄清楚的是,無論是debounce還是throttle,控制的都是回調(diào)函數(shù)的執(zhí)行,而不是事件的監(jiān)聽。
另外,debounce和throttle都只是一種思想,可以有很多種實(shí)現(xiàn),當(dāng)然也可以自己去實(shí)現(xiàn),后文中的代碼都是基于lodash中的debounce和throttle。
debounce想象這樣一個場景:電梯即將關(guān)門,這時有個人上電梯,電梯就會停止關(guān)門。過了一會兒(間隔在電梯完全關(guān)上門所需要的時間之內(nèi)),電梯又準(zhǔn)備關(guān)門,又有人上電梯,又重復(fù)之前的步驟,直到最后一個人進(jìn)來,電梯完全關(guān)上門,整個過程中電梯只關(guān)了一次門。
這個場景可以說是debounce在現(xiàn)實(shí)生活中的一個模型?;氐酱a層面:
// debounce(callback, millisecond, options) var onScroll = debounce(animation, 1000, { leading: true, trailing: false }); // right $("#container").addEventListener("scroll", onScroll); // wrong $("#container").addEventListener("scroll", function(){ debounce(callback, millisecond, options); });
debounce接受三個參數(shù):要控制的函數(shù)、兩次事件間隔的最大毫秒數(shù)、以及配置對象,返回一個函數(shù),通常直接作為事件處理函數(shù)。詳細(xì)說說第三個參數(shù)options,此參數(shù)默認(rèn)值為:
{ leading: false, trailing: true }
leading: 事件一被觸發(fā),先執(zhí)行一次回調(diào)函數(shù),再對之后的調(diào)用做控制。這樣做的好處是事件一被觸發(fā),回調(diào)就執(zhí)行,更真實(shí);
trailing: 先對回調(diào)函數(shù)做控制,直到事件觸發(fā)間隔超過設(shè)定時間,再調(diào)用回調(diào)函數(shù),像上面電梯關(guān)門的例子
兩者同時為true時,一次控制過程中回調(diào)會被執(zhí)行兩次;兩者同時為false時,回調(diào)不執(zhí)行。
常見的應(yīng)用場景:拖拽窗口的大小、實(shí)時驗(yàn)證input
throttle相比于debounce,throttle更像是一個特殊化的setInterval,就是說throttle包裝過的函數(shù)會按固定的時間間隔執(zhí)行,區(qū)別在于這個執(zhí)行跟事件的觸發(fā)有關(guān),并且不用像setInterval那樣手動取消。
throttle(callback, millisecond)
所以throttle更適用于需要不斷執(zhí)行但又需要控制執(zhí)行次數(shù)來優(yōu)化性能的函數(shù),比如在滑動時根據(jù)滑動的數(shù)據(jù)(scrollTop等)不斷改變某元素的樣式。這種情況下,間隔時間設(shè)的過長就會不流暢,過短又起不到優(yōu)化的效果。一般設(shè)為16ms,這樣可以讓幀率達(dá)到60fps,保持良好的視覺效果。說到這里就不得不提瀏覽器原生API requestAnimationFrame了。
粗略地說,requestAnimationFrame(callback)相當(dāng)于
throttle(callback, 16);
rAF的優(yōu)點(diǎn)在于它是原生的API,較為穩(wěn)定。當(dāng)然也有不少缺點(diǎn),比如需要手動的啟動和取消;瀏覽器tab不是active的時候不會被執(zhí)行;不支持IE9;
caveat雖然說debounce、throttle有很多實(shí)現(xiàn),甚至可以自己實(shí)現(xiàn),但還是推薦直接使用loadash或者underscore,專業(yè)的工具庫考慮到的事情往往比我們自己更多,不用擔(dān)心為了使用兩個函數(shù)而把整個lodash庫都引入的問題,lodash包是可定制的,具體的方法自行Google。
盡量將debounce或者throttle生成的函數(shù)直接作為事件處理函數(shù),避免寫出這種錯誤的代碼:
$("#container").addEventListener("scroll", function(){ // 這里只是生成了函數(shù),并沒有執(zhí)行,即使執(zhí)行也無法達(dá)到控制的效果 debounce(callback, millisecond, options); });
使用變量保存debounce或者throttle返回的值后,可以調(diào)用取消的方法,就像setTimeout那樣:
onScroll = debounce(animation, 1000, { leading: true, trailing: false }); $("#container").addEventListener("scroll", onScroll); onScroll.cancel();
參考文章: Debouncing and Throttling Explained Through Examples
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/91779.html
摘要:無視一定時間內(nèi)所有的調(diào)用,適合在發(fā)生頻度比較高的,處理比較重的時候使用。一定間隔內(nèi)沒有調(diào)用時,才開始執(zhí)行被調(diào)用方法。 Throttle 無視一定時間內(nèi)所有的調(diào)用,適合在發(fā)生頻度比較高的,處理比較重的時候使用。 var throttle = function (func, threshold, alt) { var last = Date.now(); threshold...
摘要:您的支持是我最大的動力,我會保證提供高質(zhì)與清晰的文章與您共同成長。一些文章中的與上面所談到的設(shè)置類似。防抖防抖技術(shù)允許我們捆綁多個連續(xù)調(diào)用成為單一的一次調(diào)用。防抖的應(yīng)用這個簡單的舉個 歡迎star和watch我的github issue blog,歡迎加入討論。您的支持是我最大的動力,我會保證提供高質(zhì)與清晰的文章與您共同成長。 節(jié)流[throttle]與防抖[debounce]在前...
摘要:背景需要包寫起來爽,然而如果遇到?jīng)]有現(xiàn)成的化的工具函數(shù),就需要自己想辦法弄出一份類型聲明文件了。最為重要的是,這種遷移方面我們可以隨意自定義化中所需要的工具函數(shù),遷移粒度都可以由自己控制。 1、背景 1.1、需要 TS 包 TypeScript 寫起來爽,然而如果遇到?jīng)]有現(xiàn)成的 TS 化的工具函數(shù),就需要自己想辦法弄出一份類型聲明文件了。 前兩天要寫的小工具庫(Typescript 語...
摘要:最簡單的案例以最簡單的情景為例在某一時刻點(diǎn)只調(diào)用一次函數(shù),那么將在時間后才會真正觸發(fā)函數(shù)。后續(xù)我們會逐漸增加黑色鬧鐘出現(xiàn)的復(fù)雜度,不斷去分析紅色鬧鐘的位置。 序 相比網(wǎng)上教程中的 debounce 函數(shù),lodash 中的 debounce 功能更為強(qiáng)大,相應(yīng)的理解起來更為復(fù)雜; 解讀源碼一般都是直接拿官方源碼來解讀,不過這次我們采用另外的方式:從最簡單的場景開始寫代碼,然后慢慢往源碼...
摘要:節(jié)流保證在一定時間內(nèi),只能觸發(fā)一次。我們在嘗試一下去抖消抖,消除抖動,感覺這個更好聽有沒有什么現(xiàn)成的上的一次發(fā)現(xiàn)源碼的經(jīng)歷以及對學(xué)術(shù)界拿來主義的思考函數(shù)節(jié)流和函數(shù)去抖應(yīng)用場景辨析函數(shù)去抖的實(shí)現(xiàn) 開篇先提幾個問題? 1.做搜索框的時候你使用什么事件?change?blur?keyup?你想要的效果是什么? 2.scroll事件怎么就觸發(fā)?是滾一段距離觸發(fā)一次?還是滾一圈觸發(fā)一次?還是滾...
閱讀 1777·2021-10-11 10:57
閱讀 2371·2021-10-08 10:14
閱讀 3407·2019-08-29 17:26
閱讀 3369·2019-08-28 17:54
閱讀 3037·2019-08-26 13:38
閱讀 2915·2019-08-26 12:19
閱讀 3622·2019-08-23 18:05
閱讀 1290·2019-08-23 17:04