Open LeoWangJ opened 5 years ago
持續觸發某個任務, 每隔一段時間觸發一次。
簡單來說 就是多久執行一次
開始執行時會先呼叫一次, 接下來依照時間戳來判斷是否重新觸發。
throttle (fn, wait) { var prev = 0 return function () { var now = +new Date() if (now - prev > wait) { fn.apply(this, arguments) prev = now } } }
經過設定的時間數後才會執行,我們透過setTimeout來判斷隔了多久觸發一次。
throttle (fn, wait) { var timeout return function () { var args = arguments if (timeout) { return false } timeout = setTimeout(() => { fn.apply(this, args) timeout = null }, wait) } }
立即執行: 執行任務時會先執行一次,但當事件停止觸發時任務就會立即停止。 例如: 在輸入註冊帳號時,設置每秒執行一次驗證註冊帳號是否符合資格,若在第2.5秒停止輸入這時只會執行兩次驗證。
非立即執行: 執行任務時會先等到指定時間到才會執行,但當事件停止觸發時依舊還會執行最後一次事件。 意思為2.5秒停止輸入等到第三秒時還會再執行一次驗證
我們想要實現出可以立即執行並且在停止輸入時還會觸發最後一次事件的方法
throttle (fn, wait) { var timeout, remaining, context, args var prev = 0 // 執行最後一次事件 var later = function () { prev = +new Date() timeout = null fn.apply(context, args) console.log('最後執行') } var throttled = function () { context = this args = arguments var now = +new Date() // 下次觸發任務(fn)的剩餘時間 remaining = wait - (now - prev) // 剩餘時間小於0,代表可以觸發事件 if (remaining <= 0) { // 確保下次還會進入setTimeout if (timeout) { clearTimeout(timeout) timeout = null } prev = now fn.apply(context, args) } else if (!timeout) { timeout = setTimeout(later, remaining) } } return throttled }
有時候並不想要上面的版本, 只想要原先的非立即執行的版本, 為了兼容這個問題我們想到了使用參數來控制想要使用哪種版本。 我們使用options作為第三個參數,而options中有兩個key:
throttle (fn, wait, options) { var timeout, remaining, context, args var prev = 0 if (!options) options = {} // 執行最後一次事件 var later = function () { prev = options.leading === false ? 0 : +new Date() timeout = null fn.apply(context, args) console.log('最後執行') } var throttled = function () { context = this args = arguments var now = +new Date() if (!prev && options.leading === false) prev = now // 下次觸發任務(fn)的剩餘時間 remaining = wait - (now - prev) // 剩餘時間小於0,代表可以觸發事件 if (remaining <= 0) { // 確保下次還會進入setTimeout if (timeout) { clearTimeout(timeout) timeout = null } prev = now fn.apply(context, args) } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining) } } return throttled }
由於我們在閉包中儲存了許多變量都沒有回收, 所以在結束這個事件時順便回收閉包變量
throttle (fn, wait, options) { var timeout, remaining, context, args var prev = 0 if (!options) options = {} // 執行最後一次事件 var later = function () { prev = options.leading === false ? 0 : +new Date() timeout = null fn.apply(context, args) if (!timeout) context = args = null console.log('最後執行') } var throttled = function () { context = this args = arguments var now = +new Date() if (!prev && options.leading === false) prev = now // 下次觸發任務(fn)的剩餘時間 remaining = wait - (now - prev) // 剩餘時間小於0,代表可以觸發事件 if (remaining <= 0) { // 確保下次還會進入setTimeout if (timeout) { clearTimeout(timeout) timeout = null } prev = now fn.apply(context, args) if (!timeout) context = args = null } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining) } } return throttled }
从搜索系统来聊聊防抖和节流 JavaScript专题之跟着underscore学防抖
節流
簡單來說 就是多久執行一次
立即執行
開始執行時會先呼叫一次, 接下來依照時間戳來判斷是否重新觸發。
非立即執行
經過設定的時間數後才會執行,我們透過setTimeout來判斷隔了多久觸發一次。
立即執行與非立即執行區別
立即執行: 執行任務時會先執行一次,但當事件停止觸發時任務就會立即停止。 例如: 在輸入註冊帳號時,設置每秒執行一次驗證註冊帳號是否符合資格,若在第2.5秒停止輸入這時只會執行兩次驗證。
非立即執行: 執行任務時會先等到指定時間到才會執行,但當事件停止觸發時依舊還會執行最後一次事件。 意思為2.5秒停止輸入等到第三秒時還會再執行一次驗證
整合兩種方式的優點
我們想要實現出可以立即執行並且在停止輸入時還會觸發最後一次事件的方法
優化
有時候並不想要上面的版本, 只想要原先的非立即執行的版本, 為了兼容這個問題我們想到了使用參數來控制想要使用哪種版本。 我們使用options作為第三個參數,而options中有兩個key:
回收變量
由於我們在閉包中儲存了許多變量都沒有回收, 所以在結束這個事件時順便回收閉包變量
參考
从搜索系统来聊聊防抖和节流 JavaScript专题之跟着underscore学防抖