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