節流就是對連續的函數觸發,在設定的間隔時間段內,只讓其執行一次。app
先來看看js高級程序設計3裏面節流的代碼函數
function throttle (method, context, wait) { clearTimeout(method.tId) method.tId = setTimeout(function () { method.call(context) }, wait) }
當函數連續執行的時候,若是以前的定時器還沒執行,就把它清除了,再重新設置一個新的定時器。this
咱們能夠對這個進行改進spa
function throttle (fn, wait) {
let timeout;
let prevTime = 0;
return function(...args) { //返回一個函數
let now = new Date();
let remaining = wait - (now - prevTime) // 下一次執行的時間,
if (remaining <=0 || remaining > wait) { // 若是下一次的時間小於等於0,馬上執行一次函數,並把時間戳改成當前的時間。
clearTimeout(timeout)
timeout = null
prevTime = now
fn.apply(this, args)
} else if (!timeout) { // 若是當前沒有定時器 那麼就新加一個定時器。
timeout = setTimeout(() => {
timeout = null;
prevTime = new Date();
fn.apply(this, args)
}, remaining)
}
}
}
第一次執行: timeout爲undefined, prevTime爲0 remaining爲負數,走if的第一個,當即執行了函數並將下次時間改爲當前時間設計
第二次執行: 下一次時間爲正,定時器仍是爲undefined,走if的第二個,設置定時器code
下一次執行(不超過wait時間內) : remaining大於0,定時器爲true,因此直接跳出blog
understore裏面的節流考慮了兩個高級的配置: 是否在第一次觸發的時候就執行函數 和 最後一次的定時器觸發的執行函數。還提供了節流的取消函數。rem
function throttle(fn, wait, option = {}) { let timeout; let prevTime = 0 let throttled = function(...args){ let now = new Date(); if (!prevTime && option.leading === false) prevTime = now; let remaining = wait - (now - prevTime); if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout) timeout = null; } prevTime = now fn.apply(this, args) } else if (!timeout && option.trailing !== false) { timeout = setTimeout(() => { prevTime = option.leading === false ? 0 : new Date; fn.apply(this, args) }) } } throttled.cancel = () => { clearTimeout(timeout); prevTime = 0; timeout = null; } return throttled }
除了加了兩個配置項和取消函數,別的基本都是同樣的。underscore
須要注意的是,首次不執行和最後不執行這兩個不能同時配置,只能配置一個。it
其實我感受防抖和節流差異不大,主要的差異在於: 在wait的時間內,反覆觸發函數的話,節流不會理會這些,而防抖的話,只要你觸發了,他就會清除以前的定時器,重新設置一個定時器。
好比說坐電梯,若是是節流的話,電梯等待時間爲5S,從第一我的進電梯開始算,到5S後他就會關門運行。
若是是防抖的話,電梯等待時間爲5S,在這5S以內,若是有人進電梯,他就會從新計時,只有在5S中沒有人進電梯了,電梯才關門運行。
function debounce (fn, wait) {
let timeout;
return function(...args) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
fn.apply(this, args)
}, wait)
}
}
返回一個函數, 先清除以前的定時器,而後再新加定時器。
underscore裏面的防抖添加了一個高級配置,是否當即執行一次函數。
function debounce(fn, wait, immediate) { let timeout; return function(...args) { let callNow = immediate && !timeout; if (timeout) clearTimeout(timeout); timeout = setTimeout(() => { timeout = null; if (!immediate) fn.apply(this, args) }, wait) if (callNow) fn.apply(this, args) } }
這裏添加了immediate這個配置項,若是爲true的話,那麼觸發第一次的時候就執行了要執行的函數,定時器裏面不執行。