摘要:函數(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é)流函數(shù)的實(shí)現(xiàn),這節(jié)將會(huì)介紹一下節(jié)流函數(shù)的兄弟 —— debounce防抖動(dòng)函數(shù)。
throttle函數(shù)是在高頻率觸發(fā)的情況下,為了防止函數(shù)的頻繁調(diào)用,將其限制在一段時(shí)間內(nèi)只會(huì)調(diào)用一次。而debounce函數(shù)則是在頻繁觸發(fā)的情況下,只在觸發(fā)的最后一次調(diào)用一次,想像一下如果我們用手按住一個(gè)彈簧,那么只有等到我們把手松開(kāi),彈簧才會(huì)彈起來(lái),下面我用一個(gè)電梯的例子來(lái)介紹debounce函數(shù)。
假如我下班的時(shí)候去坐電梯,等了一段時(shí)間后,電梯正準(zhǔn)備關(guān)上門(mén)下降,這個(gè)時(shí)候一個(gè)同事走了過(guò)來(lái),電梯門(mén)被打開(kāi),這樣電梯就會(huì)繼續(xù)等一段時(shí)間,如果中間一直有人進(jìn)來(lái),那么電梯就一直不會(huì)下降,直到最后一個(gè)人進(jìn)來(lái)后過(guò)了一定時(shí)間后還沒(méi)有下一個(gè)人進(jìn)來(lái),這時(shí)電梯才會(huì)下降。
應(yīng)用場(chǎng)景除了電梯,事實(shí)上我們還有很多應(yīng)用場(chǎng)景,比如我用鍵盤(pán)不斷輸入文字,我希望等最后一次輸入結(jié)束后才會(huì)調(diào)用接口來(lái)請(qǐng)求展示聯(lián)想詞,如果每次輸入一個(gè)字的時(shí)候就會(huì)調(diào)用接口,這樣調(diào)用未免太過(guò)于頻繁了。
沒(méi)有debounce時(shí):
有debounce時(shí):
知道debounce的工作原理了,我們可以先自己實(shí)現(xiàn)一個(gè)比較簡(jiǎn)單的debounce函數(shù)。
function debounce(func, wait) { var timeout, args, context var later = function() { func.apply(context, args) timeout = context = args = null } return function() { context = this args = arguments // 每次觸發(fā)都清理掉前一次的定時(shí)器 clearTimeout(timeout) // 只有最后一次觸發(fā)后才會(huì)調(diào)用later timeout = setTimeout(later, wait) } }
麻雀雖小,五臟俱全,不過(guò)這個(gè)函數(shù)還是有很多問(wèn)題,比如每次觸發(fā)都設(shè)置了太多的setTimeout,這樣會(huì)比較耗費(fèi)cpu,我們來(lái)看一下underscore的實(shí)現(xiàn)方式。
underscore debounce// debounce函數(shù)傳入三個(gè)參數(shù),分別是要執(zhí)行的函數(shù)func,延遲時(shí)間wait,是否立即執(zhí)行immediate // 如果immediate為true,那么就會(huì)在wait時(shí)間段一開(kāi)始就執(zhí)行一次func,之后不管觸發(fā)多少次都不會(huì)再執(zhí)行func // 在類(lèi)似不小心點(diǎn)了提交按鈕兩下而提交了兩次的情況下很有用 _.debounce = function (func, wait, immediate) { var timeout, args, context, timestamp, result; var later = function () { // 這個(gè)是最關(guān)鍵的一步,因?yàn)槊看斡|發(fā)的時(shí)候都要記錄當(dāng)前timestamp // 但是later是第一次觸發(fā)后wait時(shí)間后執(zhí)行的,_now()減去第一次觸發(fā)時(shí)的時(shí)間當(dāng)然是等于wait的 // 但是如果后續(xù)繼續(xù)觸發(fā),那么_.now() - timestamp肯定會(huì)小于wait // last是執(zhí)行l(wèi)ater的時(shí)間和上一次觸發(fā)的時(shí)間差 var last = _.now() - timestamp; // 如果在later執(zhí)行前還有其他觸發(fā),那么就會(huì)重新設(shè)置定時(shí)器 // last >= 0應(yīng)該是防止客戶端系統(tǒng)時(shí)間被調(diào)整 if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); // 如果last大于等于wait,也就是說(shuō)設(shè)置timeout定時(shí)器后沒(méi)有再觸發(fā)過(guò) } else { timeout = null; // 這個(gè)時(shí)候如果immediate不為true,就會(huì)立即執(zhí)行func函數(shù),這也是為什么immediate為true的時(shí)候只會(huì)執(zhí)行第一次觸發(fā) if (!immediate) { result = func.apply(context, args); // 解除引用 if (!timeout) context = args = null; } } }; return function () { context = this; args = arguments; // 每次觸發(fā)都用timestamp記錄時(shí)間戳 timestamp = _.now(); // 第一次進(jìn)來(lái)的時(shí)候,如果immediate為true,那么會(huì)立即執(zhí)行func var callNow = immediate && !timeout; // 第一次進(jìn)來(lái)的時(shí)候會(huì)設(shè)置一個(gè)定時(shí)器 if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; }; };
為了防止出現(xiàn)我們上面那種不停地設(shè)置定時(shí)器的情況,underscore只在later函數(shù)中在上一次定時(shí)器執(zhí)行結(jié)束后才重新設(shè)置定時(shí)器。
如果傳入的immediate為true,那么只會(huì)在第一次進(jìn)來(lái)的時(shí)候立即執(zhí)行。很明顯在上面代碼中func執(zhí)行只有兩處,一個(gè)是callNow判斷里面,一個(gè)是!immediate判斷里面,所以這樣保證了后續(xù)觸發(fā)不會(huì)再執(zhí)行func。
參考鏈接:
1、淺談throttle以及debounce的原理和實(shí)現(xiàn)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/93668.html
摘要:函數(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é)流函...
摘要:直接來(lái)分析返回的匿名函數(shù)部分。我第一次調(diào)用事件函數(shù)是在,按照設(shè)定,之后才能調(diào)用第二次方法,在這秒內(nèi),任何調(diào)用都是不執(zhí)行的。這個(gè)難點(diǎn)解決了,其他就都好說(shuō)。恩,那這個(gè)的解讀就結(jié)束了,有什么地方我沒(méi)寫(xiě)清楚的話,請(qǐng)給我留言。 剛寫(xiě)完一篇debounce(防抖)函數(shù)的實(shí)現(xiàn),我又看了下underscore.js的實(shí)現(xiàn)方法。算是趁熱打鐵,分析一下underscore里實(shí)現(xiàn)的套路。 先貼上源碼: _....
摘要:事情是如何發(fā)生的最近干了件事情,發(fā)現(xiàn)了源碼的一個(gè)。樓主找到的關(guān)于和區(qū)別的資料如下關(guān)于拿來(lái)主義為什么這么多文章里會(huì)出現(xiàn)澤卡斯的錯(cuò)誤代碼樓主想到了一個(gè)詞,叫做拿來(lái)主義。的文章,就深刻抨擊了拿來(lái)主義這一現(xiàn)象。 事情是如何發(fā)生的 最近干了件事情,發(fā)現(xiàn)了 underscore 源碼的一個(gè) bug。這件事本身并沒(méi)有什么可說(shuō)的,但是過(guò)程值得我們深思,記錄如下,各位看官仁者見(jiàn)仁智者見(jiàn)智。 平時(shí)有瀏覽別...
摘要:專(zhuān)題系列預(yù)計(jì)寫(xiě)二十篇左右,主要研究日常開(kāi)發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖節(jié)流去重類(lèi)型判斷拷貝最值扁平柯里遞歸亂序排序等,特點(diǎn)是研究和的實(shí)現(xiàn)方式。如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤剑?qǐng)務(wù)必給予指正,十分感謝。 JavaScript 專(zhuān)題系列第一篇,講解防抖,帶你從零實(shí)現(xiàn)一個(gè) underscore 的 debounce 函數(shù) 前言 在前端開(kāi)發(fā)中會(huì)遇到一些頻繁的事件觸發(fā),比如: window 的 r...
閱讀 2127·2019-08-29 16:53
閱讀 2705·2019-08-29 16:07
閱讀 2047·2019-08-29 13:13
閱讀 3271·2019-08-26 13:57
閱讀 1336·2019-08-26 13:31
閱讀 2439·2019-08-26 13:22
閱讀 1227·2019-08-26 11:43
閱讀 2089·2019-08-23 17:14