Open1
debounce/throttleのメンタルモデル
function debounce(Fn, wait) {
let timer
return function(...args) {
clearTimeout(timer)
timer = setTimeout(() => {
Fn.apply(this, args)
}, wait)
}
}
function throttle(Fn, wait) {
let shouldBlock = false
return function(...args) {
if (shouldBlock) return
shoudBlock = true
setTimeout(() => {
shoudBlock = false
}, wait)
Fn.apply(this, args)
}
}
-
timer
変数はリターン関数のスコープではなく、debounce
のスコープに置くことで、時系列の中で複数回呼び出しても、同じ変数へのアクセスが可能に(クロージャー) - 初回の
clearTimeout
はどうでも良いが、2回目からは1回目のsetTimeout
で定義されたタイマーをクリア - 定義された
wait
が切れるまで無限ループ→切れなければクリアされる -
throttle
もクロージャーを利用したほぼ同じ考え方で、shouldBlock
の値を定義された時間でtrue/false
を操作し、時系列の中で変更を達成する。
実装上のトラップ:
- リターン関数はアロー関数書かない→
this
がundefined
になる - 逆に
setTimeout
にわたす関数はアロー関数で書く→this
がないので親スコープのリターン関数のthis
を継承、これは意図通り- もしくは
let context = this
とかでcontext
を渡す - もしくは
bind
で明示的バンドする、ただし読みにくくなるかも
- もしくは