摘要:適用情景對象的事件拖拽時的事件射擊游戲中的事件文字輸入自動完成的事件實際上對于的事件,實際需求大多為停止改變大小毫秒后執行后續處理防抖而其他事件大多的需求是以一定的頻率執行后續處理節流。
區別
適用情景debounce(防抖):當調用動作n毫秒后,才會執行該動作,若在這n毫秒內又調用此動作則將重新計算執行時間。比如:如果用手指一直按住一個彈簧,它將不會彈起直到你松手為止。
throttle(節流):預先設定一個執行周期,當調用動作的時刻大于等于執行周期則執行該動作,然后進入下一個新周期。比如:將水龍頭擰緊直到水是以水滴的形式流出,那你會發現每隔一段時間,就會有一滴水流出。
window對象的resize、scroll事件
拖拽時的mousemove事件
射擊游戲中的mousedown、keydown事件
文字輸入、自動完成的keyup事件
實際上對于window的resize事件,實際需求大多為停止改變大小n毫秒后執行后續處理 (防抖);而其他事件大多的需求是以一定的頻率執行后續處理(節流)。
增加一個輔助函數 restArgs
/** * 類ES6 rest參數的實現,使某個函數具備支持rest參數的能力 * @param func 需要rest參數的函數 * @param startIndex 從哪里開始標識rest參數, 如果不傳遞, 默認最后一個參數為rest參數 * @returns {Function} 返回一個具有rest參數的函數 */ var restArgs = function (func, startIndex) { // rest參數從哪里開始,如果沒有,則默認視函數最后一個參數為rest參數 // 注意, 函數對象的length屬性, 揭示了函數的參數個數 /* ex: function add(a,b) {return a+b;} console.log(add.length;) // 2 */r startIndex = startIndex == null ? func.length - 1 : +startIndex; // 返回一個支持rest參數的函數 return function () { // 校正參數, 以免出現負值情況 var length = Math.max(arguments.length - startIndex, 0); // 為rest參數開辟數組存放 var rest = Array(length); // 假設參數從2個開始: func(a,b,*rest) // 調用: func(1,2,3,4,5); 實際的調用是:func.call(this, 1,2, [3,4,5]); for (var index = 0; index < length; index++) { rest[index] = arguments[index + startIndex]; } // 根據rest參數不同, 分情況調用函數, 需要注意的是, rest參數總是最后一個參數, 否則會有歧義 switch (startIndex) { case 0: // call的參數一個個傳 return func.call(this, rest); case 1: return func.call(this, arguments[0], rest); case 2: return func.call(this, arguments[0], arguments[1], rest); } // 如果不是上面三種情況, 而是更通用的(應該是作者寫著寫著發現這個switch case可能越寫越長, 就用了apply) var args = Array(startIndex + 1); // 先拿到前面參數 for (index = 0; index < startIndex; index++) { args[index] = arguments[index]; } // 拼接上剩余參數 args[startIndex] = rest; return func.apply(this, args); }; };debounce
返回 function 函數的防反跳版本, 將延遲函數的執行(真正的執行)在函數最后一次調用時刻的 wait 毫秒之后. 對于必須在一些輸入(多是一些用戶操作)停止到達之后執行的行為有幫助。 例如: 渲染一個Markdown格式的評論預覽, 當窗口停止改變大小之后重新計算布局, 等等.
傳參 immediate 為 true, debounce會在 wait 時間間隔的開始調用這個函數 。在類似不小心點了提交按鈕兩下而提交了兩次的情況下很有用。
var debounce = function (func, wait, immediate) { var timeout, result; var later = function (context, args) { timeout = null; if (args) result = func.apply(context, args); }; var debounced = restArgs(function (args) { // 一旦存在timeout, 意味之前嘗試調用過func // 由于debounce只認最新的一次調用, 所以之前等待執行的func都會被終止 if (timeout) clearTimeout(timeout); // 如果允許新的調用嘗試立即執行, if (immediate) { // 如果之前尚沒有調用嘗試,那么此次調用可以立馬執行,否則一定得等待之前的執行完畢 var callNow = !timeout; // 刷新timeout timeout = setTimeout(later, wait); // 如果能被立即執行,立即執行 if (callNow) result = func.apply(this, args); } else { // 否則,這次嘗試調用會延時wait個時間 timeout = delay(later, wait, this, args); } return result; }); debounced.cancel = function () { clearTimeout(timeout); timeout = null; }; return debounced; };throttle
創建并返回一個像節流閥一樣的函數,當重復調用函數的時候,至少每隔 wait毫秒調用一次該函數。對于想控制一些觸發頻率較高的事件有幫助。
默認情況下,throttle將在你調用的第一時間盡快執行這個function,并且,如果你在wait周期內調用任意次數的函數,都將盡快的被覆蓋。如果你想禁用第一次首先執行的話,傳遞{leading: false},還有如果你想禁用最后一次執行的話,傳遞{trailing: false}。
var throttle = function (func, wait, options) { var timeout, context, args, result; // 最近一次func被調用的時間點 var previous = 0; if (!options) options = {}; // 創建一個延后執行的函數包裹住func的執行過程 var later = function () { // 執行時,刷新最近一次調用時間 previous = options.leading === false ? 0 : new Date(); // 清空定時器 timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; // 返回一個throttled的函數 var throttled = function () { // ----- 節流函數開始執行---- // 我們嘗試調用func時,會首先記錄當前時間戳 var now = new Date(); // 是否是第一次調用 if (!previous && options.leading === false) previous = now; // func還要等待多久才能被調用 = 預設的最小等待期-(當前時間-上一次調用的時間) // 顯然,如果第一次調用,且未設置options.leading = false,那么remaing=0,func會被立即執行 var remaining = wait - (now - previous); // 記錄之后執行時需要的上下文和參數 context = this; args = arguments; // 如果計算后能被立即執行 if (remaining <= 0 || remaining > wait) { // 清除之前的“最新調用” if (timeout) { clearTimeout(timeout); timeout = null; } // 刷新最近一次func調用的時間點 previous = now; // 執行func調用 result = func.apply(context, args); // 如果timeout被清空了, if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { // 如果設置了trailing edge,那么暫緩此次調用嘗試的執行 timeout = setTimeout(later, remaining); } return result; }; // 可以取消函數的節流化 throttled.cancel = function () { clearTimeout(timeout); previous = 0; timeout = context = args = null; }; return throttled; };
點擊查看demo
參考文章
http://www.tuicool.com/articl...
http://blog.csdn.net/jinboker...
http://www.css88.com/doc/unde...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/50389.html
摘要:文章來源詳談防抖和節流輕松理解函數節流和函數防抖函數防抖和節流好啦,今天的小菊花課堂之的防抖與節流的內容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書示子聿》——古人學問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學習或工作中,不斷的印證著這首詩的內涵。所以,又有了此篇小菊花文章。 詳解 在前端開發中,我們經常會碰到一些會持...
摘要:文章來源詳談防抖和節流輕松理解函數節流和函數防抖函數防抖和節流好啦,今天的小菊花課堂之的防抖與節流的內容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書示子聿》——古人學問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學習或工作中,不斷的印證著這首詩的內涵。所以,又有了此篇小菊花文章。 詳解 在前端開發中,我們經常會碰到一些會持...
摘要:函數防抖簡單實現模擬請求獲取函數的作用域和變量清除定時器節流名詞解釋連續執行函數,每隔一定時間執行函數。效果函數防抖是某一段時間內只執行一次函數節流是間隔時間執行,不管事件觸發有多頻繁,都會保證在規定時間內一定會執行一次真正的事件處理函數。 防抖(debounce) 名詞解釋:在事件被觸發n秒后再執行回調函數,如果在這n秒內又被觸發,則重新計時。 使用場景:以百度輸入框例,比如你要查詢...
摘要:封裝方法也比較簡單,書中對此問題也進行了處理使用定時器,讓函數延遲秒后執行,在此秒內,然后函數再次被調用,則刪除上次的定時器,取消上次調用的隊列任務,重新設置定時器。 在實際開發中,函數一定是最實用最頻繁的一部分,無論是以函數為核心的函數式編程,還是更多人選擇的面向對象式的編程,都會有函數的身影,所以對函數進行深入的研究是非常有必要的。 函數節流 比較直白的說,函數節流就是強制規定一...
摘要:隆重請出主角防抖與節流。防抖與節流的異同相同都是防止某一時間段內,函數被頻繁調用執行,通過時間頻率控制,減少回調函數執行次數,來實現相關性能優化。參考文章分鐘理解的節流防抖及使用場景函數防抖和節流 showImg(https://segmentfault.com/img/bVburM8?w=800&h=600); 本篇課題,或許早已是爛大街的解讀文章。不過春招系列面試下來,不少伙伴們還...
摘要:防抖與節流源碼學習最近自己擼了一個輪播圖,在點擊切換的時候,為了尋求更好的用戶體驗,引入了節流,在此記錄對源碼的學習過程源碼來源防抖函數防抖使用場景現在我們需要做一個搜索框,當用戶輸入文字,執行事件的時候,需要發出異步請求去進行結果查詢。 防抖與節流(源碼學習) 最近自己擼了一個輪播圖,在點擊切換的時候,為了尋求更好的用戶體驗,引入了節流,在此記錄對源碼的學習過程源碼來源:unders...
閱讀 2398·2021-11-23 09:51
閱讀 1209·2021-11-22 13:54
閱讀 3422·2021-09-24 10:31
閱讀 1066·2021-08-16 10:46
閱讀 3619·2019-08-30 15:54
閱讀 700·2019-08-30 15:54
閱讀 2886·2019-08-29 17:17
閱讀 3154·2019-08-29 15:08