JS函數(shù)節(jié)流和防抖之間的區(qū)分和實現(xiàn)詳解
在寫JS時,這兩個函數(shù)比較常見,有時候傻傻分不清用哪個,或者說知道代碼要怎么寫,但要說出它究竟是節(jié)流函數(shù)還是防抖函數(shù)時一臉楞逼。今天有一個同學分享了這兩個的區(qū)分,我也來回顧一下,加深一下印象,以便日后用到時心里有底。PS:百度和谷歌搜索前幾個介紹都是相反介紹,本文為原創(chuàng),如有雷同純屬抄襲我的。
節(jié)流概念(Throttle)
按照設定的時間固定執(zhí)行一次函數(shù),比如200ms一次。注意:固定就是你在mousemove過程中,執(zhí)行這個節(jié)流函數(shù),它一定是200ms(你設定的定時器延遲時間)內(nèi)執(zhí)行一次。沒到200ms,一定會返回,沒有執(zhí)行回調(diào)函數(shù)的。
主要應用場景有:scroll、touchmove
防抖概念(Debounce)
抖動停止后的時間超過設定的時間時執(zhí)行一次函數(shù)。注意:這里的抖動停止表示你停止了觸發(fā)這個函數(shù),從這個時間點開始計算,當間隔時間等于你設定時間,才會執(zhí)行里面的回調(diào)函數(shù)。如果你一直在觸發(fā)這個函數(shù)并且兩次觸發(fā)間隔小于設定時間,則一定不會到回調(diào)函數(shù)那一步。
主要應用場景有:input驗證、搜索聯(lián)想、resize
節(jié)流實現(xiàn)
思路: 第一次先設定一個變量true,第二次執(zhí)行這個函數(shù)時,會判斷變量是否true,是則返回。當?shù)谝淮蔚亩〞r器執(zhí)行完函數(shù)最后會設定變量為flase。那么下次判斷變量時則為flase,函數(shù)會依次運行。
代碼一:首次不執(zhí)行
function throttle(fn,delay=100){ //首先設定一個變量,在沒有執(zhí)行我們的定時器時為null let timer = null; return function(){ //當我們發(fā)現(xiàn)這個定時器存在時,則表示定時器已經(jīng)在運行中,需要返回 if(timer) return; timer = setTimeout(()=>{ fn.apply(this,arguments); timer = null; },delay); } }
代碼二:首次執(zhí)行
function throttle2(fn,delay=100){ let last = 0; return function(){ let curr = +new Date(); if(curr - last > delay){ fn.apply(this,arguments); last = curr; } } }
防抖實現(xiàn)
思路:首次運行時把定時器賦值給一個變量,第二次執(zhí)行時,如果間隔沒超過定時器設定的時間則會清除掉定時器,重新設定定時器,依次反復,當我們停止下來時,沒有執(zhí)行清除定時器,超過一定時間后觸發(fā)回調(diào)函數(shù)。
代碼一:首次不執(zhí)行
function debounce(fn,delay=200){ let timer = null; return function(){ if(timer) clearTimeout(timer); timer = setTimeout(()=>{ fn.apply(this,arguments); timer = null; },delay); } }
代碼二:首次執(zhí)行
function debounce2(fn, delay = 200, atBegin = true) { let timer = null, last = 0,during; return function () { let self = this, args = arguments; var exec = function () { fn.apply(self, args); } if (atBegin && !timer) { exec(); atBegin = false; } else { during = Date.now() - last; if (during > delay) { exec(); } else { if (timer) clearTimeout(timer); timer = setTimeout(function () { exec(); }, delay); } } last = Date.now(); } }
上面的代碼只是我自己的一個簡單實現(xiàn),看看lodash里面的兩個核心實現(xiàn)代碼。生產(chǎn)中建議使用它們的庫,畢竟有這么多人在用,出bug的機會比較少,我上面的代碼有可能有一些情況沒考慮到。如果你發(fā)現(xiàn)有問題的,也請告訴我。
如果在項目中有需要用到的,可以直接安裝單個的NPM模塊。throttle 和 debounce
lodash使用使用文檔
lodash庫里面這兩個函數(shù)設置的參數(shù)有點復雜,記錄一下里面的參數(shù)和代碼使用。
節(jié)流(throttle)
官方文檔解釋:
創(chuàng)建一個節(jié)流函數(shù),在 wait 秒內(nèi)最多執(zhí)行 func 一次的函數(shù)。 該函數(shù)提供一個 cancel 方法取消延遲的函數(shù)調(diào)用以及 flush 方法立即調(diào)用。 可以提供一個 options 對象決定如何調(diào)用 func 方法, options.leading 與|或 options.trailing 決定 wait 前后如何觸發(fā)。 func 會傳入最后一次傳入的參數(shù)給這個函數(shù)。 隨后調(diào)用的函數(shù)返回是最后一次 func 調(diào)用的結(jié)果。
注意: 如果 leading 和 trailing 都設定為 true 則 func 允許 trailing 方式調(diào)用的條件為: 在 wait 期間多次調(diào)用。
如果 wait 為 0 并且 leading 為 false, func調(diào)用將被推遲到下一個點,類似setTimeout為0的超時。
參數(shù)
func (Function) 要節(jié)流的函數(shù) [wait=0] (number) 需要節(jié)流的毫秒 [options] (Object) 選項對象 [options.leading=true] (boolean) 指定調(diào)用在節(jié)流開始前 [options.trailing=true] (boolean) 指定調(diào)用在節(jié)流結(jié)束后
返回值 (Function)
返回節(jié)流的函數(shù)
示例
// 避免在滾動時過分的更新定位 jQuery(window).on('scroll', _.throttle(updatePosition, 100)); // 點擊后就調(diào)用 `renewToken`,但5分鐘內(nèi)超過1次。 var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); jQuery(element).on('click', throttled); // 取消一個 trailing 的節(jié)流調(diào)用 jQuery(window).on('popstate', throttled.cancel);
防抖(debounce)
創(chuàng)建一個 debounced(防抖動)函數(shù),該函數(shù)會從上一次被調(diào)用后,延遲 wait 毫秒后調(diào)用 func 方法。 debounced(防抖動)函數(shù)提供一個 cancel 方法取消延遲的函數(shù)調(diào)用以及 flush 方法立即調(diào)用。 可以提供一個 options(選項) 對象決定如何調(diào)用 func 方法,options.leading 與 options.trailing 決定延遲前后如何觸發(fā)(先調(diào)用后等待 還是 先等待后調(diào)用)。 func 調(diào)用時會傳入最后一次提供給 debounced(防抖動)函數(shù) 的參數(shù)。 后續(xù)調(diào)用的 debounced(防抖動)函數(shù)返回是最后一次 func 調(diào)用的結(jié)果。
注意: 如果 leading 和 trailing 選項為 true, 則 func 允許 trailing 方式調(diào)用的條件為: 在 wait 期間多次調(diào)用防抖方法。
如果 wait 為 0 并且 leading 為 false, func調(diào)用將被推遲到下一個點,類似setTimeout為0的超時。
參數(shù)
func (Function) 要防抖動的函數(shù) [wait=0] (number) 需要延遲的毫秒數(shù) [options] (Object) 選項對象 [options.leading=false] (boolean) 指定調(diào)用在延遲開始前 [options.maxWait] (number) 設置 func 允許被延遲的最大值 [options.trailing=true] (boolean) 指定調(diào)用在延遲結(jié)束后
返回值 (Function)
返回具有防抖動功能的函數(shù)
示例
// 避免窗口在變動時出現(xiàn)昂貴的計算開銷。 jQuery(window).on('resize', _.debounce(calculateLayout, 150)); // 當點擊時 `sendMail` 隨后就被調(diào)用。 jQuery(element).on('click', _.debounce(sendMail, 300, { 'leading': true, 'trailing': false })); // 確保 `batchLog` 調(diào)用1次之后,1秒內(nèi)會被觸發(fā)。 var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); var source = new EventSource('/stream'); jQuery(source).on('message', debounced); // 取消一個 trailing 的防抖動調(diào)用 jQuery(window).on('popstate', debounced.cancel);
以上就是這篇節(jié)流和防抖的全部介紹,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JavaScript內(nèi)置對象math,global功能與用法實例分析
這篇文章主要介紹了JavaScript內(nèi)置對象math,global功能與用法,結(jié)合實例形式分析了javascript中內(nèi)置對象math與global的基本概念、功能及使用方法,需要的朋友可以參考下2019-06-06JavaScript 手動實現(xiàn)instanceof的方法
instanceof運算符用于檢測構(gòu)造函數(shù)的prototype屬性是否出現(xiàn)在某個實例對象的原型鏈上,本文重點給大家介紹JavaScript手動實現(xiàn)instanceof的問題,感興趣的朋友跟隨小編一起看看吧2021-10-10使用js實現(xiàn)按鈕控制文本框加1減1應用于小時+分鐘
正如標題所言使用js實現(xiàn)按鈕控制文本框加1減1,此類主要應用于小時+分鐘,下面有個不錯的示例,喜歡的朋友可以參考下2013-12-12JavaScript使用位運算符判斷奇數(shù)和偶數(shù)的方法
這篇文章主要介紹了JavaScript使用位運算符判斷奇數(shù)和偶數(shù)的方法,涉及javascript位運算的使用技巧,需要的朋友可以參考下2015-06-06JavaScript中Function與Object的關(guān)系
本文主要介紹了JavaScript中Function與Object的關(guān)系,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-05-05JavaScript代碼實現(xiàn)禁止右鍵、禁選擇、禁粘貼、禁shift、禁ctrl、禁alt
這篇文章主要介紹了JavaScript代碼實現(xiàn)禁止右鍵、禁選擇、禁粘貼、禁shift、禁ctrl、禁alt,需要的朋友可以參考下2015-11-11JavaScript中數(shù)據(jù)結(jié)構(gòu)與算法(三):鏈表
這篇文章主要介紹了JavaScript中數(shù)據(jù)結(jié)構(gòu)與算法(三):鏈表,本文分別講解了單鏈表與雙鏈表以及增加節(jié)和刪除節(jié)的代碼實例,需要的朋友可以參考下2015-06-06