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