網站遷移公告:很高興各位讀者近年來的陪伴!本部落格目前正在緩步遷移至 jingsu.fyi (個人內容) 以及 parseweb.dev (技術相關內容)
文章

前端面試手寫練習 - throttle (進階)

文章發表於

問題

在先前的版本中,似乎少了一些使用上彈性以及功能,想像一下,如果今天是實作一個無限滾動的功能,每當使用者滾動到底部時才會載入更多的資料,但聰明的你發現不需要每次滑動時都去呼叫載入更多,這毫無意義。

這時候剛好想上次有實作過的 throttle,所以就開心地將它拿來使用,所以行為看起來會是以下範例:

<!DOCTYPE html>
<html>

<head>
  <title>Parcel Sandbox</title>
  <meta charset="UTF-8" />
  <link rel="stylesheet" href="/styles.css" />
</head>

<body>
  <h1>Hello world</h1>
</body>

</html>

不知道各位讀者有沒有發現問題?如果將 loadMoreContent 用先前的 throttle 包起來,會發現每次滾動到底部時就沒反應了,原因是最後一次滑動事件被忽略了。

主要是先前的 throttle 只會確保不是冷卻時間時才會執行,這代表它可以確保第一次 (稱作 leading) 滾動時會執行 loadMoreContent,但當滾動到底部時,throttle 可能因為還在冷卻時間,而被忽略掉了。

所以本篇文章就是要實作一個更進階的 throttle,讓可以讓開發者自行決定是否要在 leading 與 trailing 時執行。

function throttle(
func: Function,
wait: number,
options: { leading?: boolean; trailing?: boolean }
): Function

練習區

在了解問題後,可以嘗試先寫下您的思路,再到下方的練習區域實際寫出程式碼。

import { add } from './add';

describe('add', () => {
  test('Commutative Law of Addition', () => {
    expect(add(1, 2)).toBe(add(2, 1));
  });
});

Open browser consoleTests

實作完成後,可以將您的程式碼複製到上面的範例中,理論上在滑動到底部時就可以正常載入更多資料了。

筆者思路

  1. 我們可以先實作一個 leading 跟 trailing 都為 true 的版本。
  2. 只需基於原本的 throttle 函式,加上 savedArgs 跟 savedThis 來儲存最後一次的參數與 this。
  3. 並在 setTimeout 結束時,先執行一次 func,同時檢查是否有 savedArgs,如果有的話就將 savedArgs 與 savedThis 設為 null,並在冷卻時間結束後執行一次 func。
  4. 最後再加上 options 的判斷,如果 leading 與 trailing 為 false,則不執行 func。

筆者解答

function throttle(func, wait, options = { leading: true, trailing: true }) {
let isThrottled = false
let savedArgs
let savedThis
const later = () => {
if (savedArgs && options.trailing) {
func.apply(savedThis, savedArgs)
savedThis = savedArgs = null
setTimeout(later, wait)
} else {
isThrottled = false
}
}
return function (...args) {
if (isThrottled) {
savedThis = this
savedArgs = args
return
}
isThrottled = true
setTimeout(later, wait)
if (options.leading) {
func.apply(this, args)
}
}
}

相關題目

  1. bigfrontend.dev - throttle with leading & trailing option

延伸閱讀

  1. Debounce vs Throttle: Definitive Visual Guide
如果您喜歡這篇文章,請點擊下方按鈕分享給更多人,這將是對筆者創作的最大支持和鼓勵。