函數(shù)防抖(debounce)
防抖函數(shù) debounce 指的是某個(gè)函數(shù)在某段時(shí)間內(nèi),無(wú)論觸發(fā)了多少次回調(diào),都只執(zhí)行最后一次。假設(shè)我們?cè)O(shè)置了一個(gè)等待3秒的函數(shù),在這3秒內(nèi)如果遇到函數(shù)調(diào)用請(qǐng)求就重新計(jì)時(shí)3秒,直至新的3秒內(nèi)沒有函數(shù)調(diào)用請(qǐng)求,此時(shí)執(zhí)行函數(shù),不然就依次類推重新計(jì)時(shí)。
原理與實(shí)現(xiàn)
實(shí)現(xiàn)原理就是利用定時(shí)器,函數(shù)第一次執(zhí)行時(shí)設(shè)定一個(gè)定時(shí)器,之后調(diào)用時(shí)發(fā)現(xiàn)已經(jīng)設(shè)定過定時(shí)器就清空之前的定時(shí)器,并重新設(shè)定一個(gè)新的定時(shí)器,如果存在沒有被清空的定時(shí)器,當(dāng)定時(shí)器結(jié)束后觸發(fā)函數(shù)執(zhí)行。
// func 是用戶傳入需要防抖的函數(shù)
// wait 是等待時(shí)間
const debounce = ( func, wait = 100 ) => {
// 設(shè)置一個(gè)定時(shí)器 (id)
let timer = 0
// 這里放回的函數(shù)是每次用戶實(shí)際調(diào)用的防抖函數(shù)
// 如果已經(jīng)設(shè)置過定時(shí)器就清空上一次的定時(shí)器
// 開始一個(gè)新的定時(shí)器,延遲執(zhí)行用戶傳入的方法
return function(...args) {
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, wait )
}
}
函數(shù)節(jié)流(throttle)
規(guī)定在一個(gè)單位時(shí)間內(nèi),只能觸發(fā)一次函數(shù)。如果這個(gè)單位時(shí)間內(nèi)觸發(fā)多次函數(shù),只有一次生效。即每隔一段時(shí)間后執(zhí)行一次,也就是降低頻率,將高頻操作優(yōu)化成低頻操作。通常使用場(chǎng)景:滾動(dòng)條事件 或者 resize 事件,通常每隔 100~500ms 執(zhí)行一次即可
// func 是用戶傳入需要防抖的函數(shù)
// wait 是等待時(shí)間
const throttle = (func, wait = 100) => {
// 上一次執(zhí)行函數(shù)的時(shí)間
let lastTime = 0
return (...args) => {
let now = new Date().getTime()
// 將當(dāng)前時(shí)間和上一次執(zhí)行函數(shù)時(shí)間對(duì)比
// 如果差值大于設(shè)置的時(shí)間就執(zhí)行函數(shù)
if(now - lastTime > await) {
func.apply(this, args)
lastTime = now
}
}
}
let i = 1
window.addEventListener('scroll', throttle(() => {
console.log('圖片懶加載')
console.log(i)
i += 1
}, 350))
總結(jié)
函數(shù)防抖和函數(shù)節(jié)流都是防止某一時(shí)間頻繁觸發(fā),但是原理卻不同。函數(shù)防抖是某一段時(shí)間內(nèi)只執(zhí)行一次,而函數(shù)節(jié)流是間隔時(shí)間執(zhí)行。
debounce
search搜索聯(lián)想,用戶在不斷輸入值時(shí),用防抖來(lái)節(jié)約請(qǐng)求資源。window觸發(fā)resize的時(shí)候,不斷的調(diào)整瀏覽器窗口大小會(huì)不斷的觸發(fā)這個(gè)事件,用防抖來(lái)讓其觸發(fā)一次
throttle
鼠標(biāo)不斷點(diǎn)擊觸發(fā),mousedown(單位時(shí)間內(nèi)只觸發(fā)一次)監(jiān)聽滾動(dòng)事件,比如是否滑倒底部自動(dòng)加載更多,用throttle來(lái)判斷