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