摘要:淺談以及的原理和實現(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)用進(jìn)行注冊遇到多次調(diào)用的時候清
淺談throttle以及debounce的原理和實現(xiàn) 背景
日常開發(fā)中,我們經(jīng)常會遇到一些需要節(jié)流調(diào)用,或者壓縮調(diào)用次數(shù)的情況,例如之前我在完成一個需求的時候,就遇到了因為后端并發(fā)問題,導(dǎo)致收到多條socket信息從而導(dǎo)致函數(shù)被重復(fù)調(diào)用的情況,當(dāng)時的做法是通過setTimeout對函數(shù)的調(diào)用進(jìn)行注冊,遇到多次調(diào)用的時候,清空前一次的調(diào)用,以后一次為準(zhǔn).后來在閱讀underscore源碼的時候,發(fā)現(xiàn)這種做法與debounce以及throttle的實現(xiàn)不謀而合.因而簡單記錄一下.
throttle與debouncethrottle與debounce在用于控制函數(shù)的多次調(diào)用的時候,非常的有效.throttle函數(shù)能夠控制目標(biāo)函數(shù)在一定的時間內(nèi)最多只會調(diào)用一次.而debounce函數(shù),則可以壓縮調(diào)用的次數(shù),把多次函數(shù)調(diào)用壓縮成只調(diào)用一次(多次的函數(shù)調(diào)用之間的間隔不能超過規(guī)定的時間間隔).
這樣文字描述起來可能比較難理解,不過不要緊,當(dāng)初我在看underscore源碼的時候,也是非常難以理解這兩個函數(shù)的需求,感覺好像都差不多一樣.而且underscore在1.1.3版本中,采用了相同的底層實現(xiàn),只是接口傳入的參數(shù)不同而已.因而我們這里采用一個坐電梯的例子來說明.
假設(shè)你正在準(zhǔn)備乘坐電梯,并且電梯門準(zhǔn)備關(guān)上然后上升的時候,你的同事來了,出于禮貌,我們需要停止電梯的關(guān)閉,讓同事進(jìn)入.假設(shè)源源不斷的有同事進(jìn)來的話,電梯就需要處于一種待機的狀態(tài),一直等待人員的進(jìn)入,直到?jīng)]有新的同事進(jìn)入或者說電梯滿了,這個時候,電梯才能運行.另外,同事的進(jìn)入需要在電梯門的關(guān)閉之前,否則的話,就只能等下一趟了.
換成圖示我們可以這么理解
上面一排方塊為函數(shù)的調(diào)用,下面的方塊則是函數(shù)實際的運行.我們可以看到,即使函數(shù)多次調(diào)用,在短暫的暫停后,函數(shù)只會運行一次.
debounce運用場景既然debounce函數(shù)可以把多次的函數(shù)調(diào)用壓縮成一次,那么我們在進(jìn)行Markdown渲染的時候,就可以排上用場了.如果我們在每一次鍵盤的敲擊都進(jìn)行一次Markdown渲染,必然會造成部分的計算冗余,同時也可能因為多次無畏的渲染導(dǎo)致頁面卡頓,影響體驗,因而我們可以使用debounce函數(shù),把Markdown的渲染進(jìn)行壓縮,只在鍵盤敲擊結(jié)束了一定的時間后((可以完成一次詞語或者語句的輸入),再進(jìn)行渲染,能夠減少許多冗余的計算,提高體驗.
throttle電梯throttle電梯不想debounce電梯一樣會無限的等待,而是我們設(shè)定一個時間,例如10s,那么10s內(nèi),其他的人可以不斷的進(jìn)入電梯,但是,一旦10s過去了,那么無論如何,電梯都會進(jìn)入運行的狀態(tài).
換成圖示,我們可以這么理解
上面一排的方塊是函數(shù)的調(diào)用,我們可以看到,及時進(jìn)行了多次的函數(shù)調(diào)用,函數(shù)也只會在隔一段時間實際運行一次,不會每一次的函數(shù)調(diào)用都運行
throttle也有另外一個稱號,就是節(jié)流函數(shù),顧名思義就是能夠節(jié)省函數(shù)調(diào)用時的資源消耗,達(dá)到防止系統(tǒng)資源被一直大量占用,從而影響其他函數(shù)執(zhí)行的情況.throttle一個運用的比較廣泛的場景則是通過對scroll函數(shù)進(jìn)行節(jié)流,因為每一次滾動頁面,都有進(jìn)行資源的消耗計算,但是完全沒必要每一次滾動時間觸發(fā)的時候,都進(jìn)行計算,這樣有可能會導(dǎo)致大量的計算堆積而出現(xiàn)跳幀的情況發(fā)生,因而我們需要使用throttle函數(shù)進(jìn)行節(jié)流,在滾動事件發(fā)生了一段事件后,再統(tǒng)一的進(jìn)行處理,只要時間設(shè)置的合理,用戶一般是感知不到的.
debounce與throttle的原理與實現(xiàn)解釋的再多,也不如我們直接自己實現(xiàn)一遍debounce與throttle,這樣對于兩個函數(shù)的運用和理解,都會更上一層樓.debounce與throttle在許多的庫,例如jQuery,loadash以及underscore中都有實現(xiàn),這里采用underscore的1.1.3版本的實現(xiàn),非常簡單而且能夠達(dá)到目的(其實主要是最近在看underscore源碼)
代碼如下
// throttle 和 debouce 函數(shù)的底層實現(xiàn) var limit = function(func, wait, debounce) { var timeout; return function() { var context = this, args = arguments; // 封裝函數(shù),用于延遲調(diào)用 var throttler = function() { // 只是節(jié)流函數(shù)的時候,對其timeout進(jìn)行賦值為null,這樣可以設(shè)置下一次的setTimtout timeout = null; func.apply(context, args); }; // 如果debouce是true的話,前一個函數(shù)的調(diào)用timeout會被清空,不會被執(zhí)行 ? ? ? ? ? ?// 就是debounce函數(shù)的調(diào)用,這個前一個函數(shù)的不會執(zhí)行.下面會重新設(shè)定setTimeout用于 ? ? ? ? ? ?// 執(zhí)行這一次的調(diào)用. ? ? ? ? ? ?// 但是如果是throttle函數(shù),則會執(zhí)行前一個函數(shù)的調(diào)用,同時下面的setTimeout在 ? ? ? ? ? ?// 函數(shù)沒有運行的時候,是無法再次設(shè)定的. ? ? ? ? ? ?if (debounce) clearTimeout(timeout); // 如果debouce是true 或者 timeout 為空的情況下,設(shè)置setTimeout if (debounce || !timeout) timeout = setTimeout(throttler, wait); }; }; // throttle 節(jié)流函數(shù) _.throttle = function(func, wait) { return limit(func, wait, false); }; // debouce 多次調(diào)用,只執(zhí)行最后一次. _.debounce = function(func, wait) { return limit(func, wait, true); };
代碼上面都加了注釋,比較好理解,而且也比較簡單.通過代碼,我們可以更加進(jìn)一步的理解debounce與throttle的原理以及實現(xiàn),主要都是通過標(biāo)志位來判斷是否要清空setTimeout以及是否要生成新的setTimeout
至此,debounce與throttle的原理以及實現(xiàn)基本就介紹完成了.寫的不是特別的流暢,大家湊合著看,主要還是用于記錄在日常工作中以及在源碼閱讀中遇到的一些小發(fā)現(xiàn)和小靈感.
參考jQuery throttle / debounce: Sometimes, less is more!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/85195.html
摘要:如果想忽略結(jié)尾邊界上的調(diào)用,傳入返回客戶調(diào)用函數(shù)上次執(zhí)行時間點延遲執(zhí)行函數(shù)若設(shè)定了開始邊界不執(zhí)行選項,上次執(zhí)行時間始終為首次執(zhí)行時,如果設(shè)定了開始邊界不執(zhí)行選項,將上次執(zhí)行時間設(shè)定為當(dāng)前時間。 Underscore.js 是一個很精干的庫,壓縮后只有5.2KB。它提供了幾十種函數(shù)式編程的方法,彌補了標(biāo)準(zhǔn)庫的不足,大大方便了JavaScript的編程。 本文僅探討Unde...
摘要:如果想忽略結(jié)尾邊界上的調(diào)用,傳入返回客戶調(diào)用函數(shù)上次執(zhí)行時間點延遲執(zhí)行函數(shù)若設(shè)定了開始邊界不執(zhí)行選項,上次執(zhí)行時間始終為首次執(zhí)行時,如果設(shè)定了開始邊界不執(zhí)行選項,將上次執(zhí)行時間設(shè)定為當(dāng)前時間。 文章轉(zhuǎn)自:https://blog.coding.net/blog/...注: _.throttle 和 _.debounce是Underscore.js庫的兩個針對函數(shù)節(jié)流的方法,用于處理高頻...
摘要:隆重請出主角防抖與節(jié)流。防抖與節(jié)流的異同相同都是防止某一時間段內(nèi),函數(shù)被頻繁調(diào)用執(zhí)行,通過時間頻率控制,減少回調(diào)函數(shù)執(zhí)行次數(shù),來實現(xiàn)相關(guān)性能優(yōu)化。參考文章分鐘理解的節(jié)流防抖及使用場景函數(shù)防抖和節(jié)流 showImg(https://segmentfault.com/img/bVburM8?w=800&h=600); 本篇課題,或許早已是爛大街的解讀文章。不過春招系列面試下來,不少伙伴們還...
摘要:防抖和節(jié)流嚴(yán)格算起來應(yīng)該屬于性能優(yōu)化的知識,但實際上遇到的頻率相當(dāng)高,處理不當(dāng)或者放任不管就容易引起瀏覽器卡死。 防抖和節(jié)流嚴(yán)格算起來應(yīng)該屬于性能優(yōu)化的知識,但實際上遇到的頻率相當(dāng)高,處理不當(dāng)或者放任不管就容易引起瀏覽器卡死。所以還是很有必要早點掌握的。(信我,你看完肯定就懂了) 從滾動條監(jiān)聽的例子說起 先說一個常見的功能,很多網(wǎng)站會提供這么一個按鈕:用于返回頂部。showImg(ht...
摘要:函數(shù)分析標(biāo)簽空格分隔本文是源碼剖析系列第六篇文章,上節(jié)我們介紹了節(jié)流函數(shù)的實現(xiàn),這節(jié)將會介紹一下節(jié)流函數(shù)的兄弟防抖動函數(shù)。函數(shù)是在高頻率觸發(fā)的情況下,為了防止函數(shù)的頻繁調(diào)用,將其限制在一段時間內(nèi)只會調(diào)用一次。 underscore debounce函數(shù)分析 標(biāo)簽(空格分隔): underscore 本文是underscore源碼剖析系列第六篇文章,上節(jié)我們介紹了throttle節(jié)流函...
閱讀 3054·2021-11-11 16:55
閱讀 3170·2021-10-18 13:34
閱讀 592·2021-10-14 09:42
閱讀 1642·2021-09-03 10:30
閱讀 848·2021-08-05 10:02
閱讀 970·2019-08-30 11:27
閱讀 3484·2019-08-29 15:14
閱讀 1254·2019-08-29 13:02