最開始寫的防抖函數(shù)
function debounce(fn, delay) {
let timer;
// 返回一個(gè)函數(shù),這個(gè)函數(shù)會(huì)在一個(gè)時(shí)間區(qū)間結(jié)束后的 delay 毫秒時(shí)執(zhí)行 fn 函數(shù)
return function () {
// 保存函數(shù)調(diào)用時(shí)的上下文和參數(shù)尘奏,傳遞給 fn
let context = this
let args = arguments
// 每次這個(gè)返回的函數(shù)被調(diào)用纯续,就清除定時(shí)器魏蔗,以保證不執(zhí)行 fn
clearTimeout(timer)
// 當(dāng)返回的函數(shù)被最后一次調(diào)用后(也就是用戶停止了某個(gè)連續(xù)的操作)澈魄,
// 再過 delay 毫秒就執(zhí)行 fn
timer = setTimeout(function () {
fn.apply(context, args)
}, delay)
}
}
寫兩個(gè)按鈕來執(zhí)行
<input type="button" value="觸發(fā)按鈕" onclick="btnclick()"/>
<input id="btn" type="button" value="監(jiān)聽按鈕"/>
這里 問題就來了 比如點(diǎn)擊兩次 這樣做的話就會(huì)出現(xiàn) 2秒之后 打印2次console
function btnclick() {
debounce(function () {
console.log('觸發(fā)按鈕的點(diǎn)擊事件')
}, 1000)()
}
但是下面這樣寫就是正確的 連續(xù)點(diǎn)擊兩次 最后一次點(diǎn)擊兩秒之后打印console
let btn = document.getElementById('btn')
btn.addEventListener('click', debounce(() => {
console.log('監(jiān)聽按鈕')
}, 1000))
這里困惑了很久才發(fā)現(xiàn) 實(shí)際上事件監(jiān)聽相當(dāng)于是吧debounce函數(shù)的返回值先拿到 再在點(diǎn)擊的時(shí)候執(zhí)行這個(gè)返回函數(shù)
而觸發(fā)按鈕是每次點(diǎn)擊都會(huì)執(zhí)行debounce這個(gè)函數(shù) 執(zhí)行debouce就會(huì)初始化 let timer 下面的clearTimeout就沒有辦法清除定時(shí)器
解決辦法: 直接把這個(gè)timer給this 每次執(zhí)行的時(shí)候都不會(huì)初始化timer
當(dāng)然 比較笨的辦法就是先把debouce函數(shù)的返回函數(shù)緩存下來 點(diǎn)擊的時(shí)候才執(zhí)行
let d = debounce(function () {
console.log('事件函數(shù)')
}, 1000)
function btnclick() {
d()
}
function debounce(fn, delay) {
// 返回一個(gè)函數(shù)厢蒜,這個(gè)函數(shù)會(huì)在一個(gè)時(shí)間區(qū)間結(jié)束后的 delay 毫秒時(shí)執(zhí)行 fn 函數(shù)
return function () {
// 保存函數(shù)調(diào)用時(shí)的上下文和參數(shù)轻纪,傳遞給 fn
let context = this
let args = arguments
// 每次這個(gè)返回的函數(shù)被調(diào)用齿梁,就清除定時(shí)器催植,以保證不執(zhí)行 fn
clearTimeout(this.timer)
// 當(dāng)返回的函數(shù)被最后一次調(diào)用后(也就是用戶停止了某個(gè)連續(xù)的操作),
// 再過 delay 毫秒就執(zhí)行 fn
this.timer = setTimeout(function () {
fn.apply(context, args)
}, delay)
}
}