closure 練習題


Posted by s103071049 on 2021-08-05

throttle 與 debounce

debounce (延遲執行)

應用: auto complete input

打字的間隔很近不用那麼快發 request。call api 的 function 不要每打一次就出發,而是要確保 x 秒後才觸發。

// 每當 input 的內容有變動,就呼叫 handleChange
$('input').change(handleChange)

// 讓原本發後端 api 的函式 debounce
const debouncedFn = debounce(getAutoSuggestions, 250)

function handleChange(e) {
  // 拿到 input 的值
  const value = e.target.value

  // 發 api 去後端拿搜尋建議,然後 render 出來
  // 細節我就不寫了
  // 在 250ms 內重複呼叫的話不會有反應
  debouncedFn(value)
}

這樣的做法不是正確的。

function debounce(fn, ms) {
  setTimeout(() => {
    fn() // 執行 function
  }, ms)
}

打第一個字 => 250 毫秒才會執行 getAutoSuggestions
打第二個字 => 250 毫秒才會執行 getAutoSuggestions,但可能第一個已經發出去了

所以在 setTimeout 到期之前若觸發 handleChange 應該將前一個 request 給取消

$('input').change(handleChange)

function handleChange(e) {
  const value = e.target.value
  setTimeout(() => {
    getAutoSuggestions(value)
  }, 250)
}

加上 timer 目的是達到 setTimeout 到期之前若觸發 handleChange 應該將前一個 request 給取消

若 timer 有東西就表示有計時器在這邊等,因此若計時器還沒觸發前又再呼叫一次,就要再重新設定計時器 => clearTimeout(timer)

我設置一個計時器 250 毫秒會被觸發
打第一個字 => timer => 250 ms
打第二個字 => 發現已有 timer => 將打第一個字的 timer (x) => 重設一個新的 timer => 250 ms
以此類推

$('input').change(handleChange)

let timer
function handleChange(e) {
  const value = e.target.value
  if (timer) {
    clearTimeout(timer)
  }
  timer = setTimeout(() => {
    getAutoSuggestions(value)
  }, 250)
}

要讓所有人都使用,做成一個函式
return 的 function 就是 debouncedFn

const debouncedFn = debounce(getAutoSuggestions, 250)

function debounce(fn, ms) {
  let timer
  return function(...args) {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn(...args)
    }, ms)
  }
}

debouncedFn()
debouncedFn()

memoize

不想改到原本的 function 希望創造出新的 function 有原本的功能

會出事 => if (!cached[num]) => 如果 complex function 某個 input 的回傳結果為 0 => 這個的檢查就會是 true => 就會再重新算一遍

參數有多個就會碰到 cached 的 key 怎麼存。

function memorize(fn) {
  const cached = {}
  return function(num) {
   if (!cached[num]) {
      cached[num] = fn(num)
    }
    return cached[num]
  }
}
const memorizeFn = memorize(complex)
console.log(memorizeFn(10))

function complex(n) {
  return n * n
}

解決出事問題 => if (cached[num] === undefined) 如果 function 回傳 undefined 這就要去看原本 function 的實作是甚麼

若想做到完美,cached[num] 可以存一個物件

如果答案是 falsey 的話,就不會過判斷,如果算過因為是物件所以答案一定會是 truesey

function memorize(fn) {
  const cached = {}
  return function(num) {
    if (!cached[num]) {
      cached[num] = {
        value: fn(num)
      }
    }
    return cached[num].value
  }
}

閉包的學習技巧

一行一行看、一行一行執行


#closure #practice







Related Posts

JavaScript 捉摸不定的 This

JavaScript 捉摸不定的 This

腳踏實地往前走 — 團隊的可執行事項

腳踏實地往前走 — 團隊的可執行事項

'vite'不是內部或外部命令、可執行的程式或批次檔的各種解法

'vite'不是內部或外部命令、可執行的程式或批次檔的各種解法


Comments