前端面試手寫練習 - throttle (進階)
- 文章發表於
問題
在先前的版本中,似乎少了一些使用上彈性以及功能,想像一下,如果今天是實作一個無限滾動的功能,每當使用者滾動到底部時才會載入更多的資料,但聰明的你發現不需要每次滑動時都去呼叫載入更多,這毫無意義。
這時候剛好想上次有實作過的 throttle,所以就開心地將它拿來使用,所以行為看起來會是以下範例:
不知道各位讀者有沒有發現問題?如果將 loadMoreContent
用先前的 throttle
包起來,會發現每次滾動到底部時就沒反應了,原因是最後一次滑動事件被忽略了。
主要是先前的 throttle
只會確保不是冷卻時間時才會執行,這代表它可以確保第一次 (稱作 leading) 滾動時會執行 loadMoreContent
,但當滾動到底部時,throttle
可能因為還在冷卻時間,而被忽略掉了。
所以本篇文章就是要實作一個更進階的 throttle
,讓可以讓開發者自行決定是否要在 leading 與 trailing 時執行。
function throttle(func: Function,wait: number,options: { leading?: boolean; trailing?: boolean }): Function
練習區
在了解問題後,可以嘗試先寫下您的思路,再到下方的練習區域實際寫出程式碼。
實作完成後,可以將您的程式碼複製到上面的範例中,理論上在滑動到底部時就可以正常載入更多資料了。
筆者思路
- 我們可以先實作一個
leading
跟trailing
都為true
的版本。 - 只需基於原本的
throttle
函式,加上savedArgs
跟savedThis
來儲存最後一次的參數與this
。 - 並在 setTimeout 結束時,先執行一次
func
,同時檢查是否有savedArgs
,如果有的話就將savedArgs
與savedThis
設為null
,並在冷卻時間結束後執行一次func
。 - 最後再加上
options
的判斷,如果leading
與trailing
為false
,則不執行func
。
筆者解答
function throttle(func, wait, options = { leading: true, trailing: true }) {let isThrottled = falselet savedArgslet savedThisconst later = () => {if (savedArgs && options.trailing) {func.apply(savedThis, savedArgs)savedThis = savedArgs = nullsetTimeout(later, wait)} else {isThrottled = false}}return function (...args) {if (isThrottled) {savedThis = thissavedArgs = argsreturn}isThrottled = truesetTimeout(later, wait)if (options.leading) {func.apply(this, args)}}}