函數防抖就是,延遲一段時間再執行函數,若是這段時間內又觸發了該函數,則延遲從新計算;javascript
// 簡單實現 function debounce(fn, wait) { let t return () => { let context = this let args = arguments if (t) clearTimeout(t) t= setTimeout(() => { fn.apply(context, args) }, wait) } }
// underscore.js debounce // // Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. _.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; // 處理時間 var later = function() { var last = _.now() - timestamp; if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); // 10ms 6ms 4ms } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } };
節流:函數間隔一段時間後才能再觸發,避免某些函數觸發頻率太高,好比滾動條滾動事件觸發的函數。java
// 簡單實現 function throttle (fn, wait, mustRun) { let start = new Date() let timeout return () => { // 在返回的函數內部保留上下文和參數 let context = this let args = arguments let current = new Date() clearTimeout(timeout) let remaining = current - start // 達到了指定觸發時間,觸發該函數 if (remaining > mustRun) { fn.apply(context, args) start = current } else { // 不然wait時間後觸發,閉包保留一個timeout實例 timeout = setTimeout(fn, wait); } } }
// underscore.js throttle // // Returns a function, that, when invoked, will only be triggered at most once // during a given window of time. Normally, the throttled function will run // as much as it can, without ever going more than once per `wait` duration; // but if you'd like to disable the execution on the leading edge, pass // `{leading: false}`. To disable execution on the trailing edge, ditto. _.throttle = function(func, wait, options) { var context, args, result; var timeout = null; var previous = 0; if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { var now = _.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; };