轉(zhuǎn)載自https://segmentfault.com/a/1190000018428170
原作者安歌
假設(shè)有如下功能,監(jiān)視瀏覽器滾動事件,返回滾動條與頂部的距離:
function showTop(){
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條距頂部距離:'+scrollTop)
}
window.onscroll = showTop
但是這個函數(shù)的運(yùn)行頻率實(shí)在太高了筒繁,不可能把瀏覽器的性能浪費(fèi)在這里。
防抖
- 定義
對于短時間內(nèi)連續(xù)觸發(fā)的事件门粪,防抖的含義就是讓某個時間期限內(nèi)鹦付,處理函數(shù)只執(zhí)行一次屎即。 - 思路
- 在第一次觸發(fā)事件后贡翘,不要立即執(zhí)行函數(shù)蚜厉,而是給出一個期限值长已。比如1000ms
- 如果1000ms內(nèi)沒有再次觸發(fā)事件則執(zhí)行處理函數(shù)
- 如果1000ms內(nèi)再次觸發(fā)了該事件,則當(dāng)前的計(jì)時取消,重新開始計(jì)時术瓮。
- 效果
如果短時間內(nèi)大量觸發(fā)同一事件康聂,那么只會執(zhí)行一次處理函數(shù) - 實(shí)現(xiàn)
// fn:需要防抖的函數(shù) delay:防抖的期限值,ms
function debounce(fn,delay){
let timer = null // 借助閉包避免全局污染
return function(){
// 如果當(dāng)前正在計(jì)時過程中,又觸發(fā)了同一事件胞四,則取消當(dāng)前計(jì)時恬汁,重新開始計(jì)時
if(timer){
clearTimeout(timer)
timer = setTimeout(fn,delay)
}else{
// 當(dāng)前沒有在計(jì)時,觸發(fā)事件則開始計(jì)時
timer = setTimeout(fn,delay)
}
/*上述代碼的timer=setTimeout(fn,delay)是一定會執(zhí)行的辜伟,所以可以簡化
if(timer){
clearTimeout(timer)
}
timer = setTimeout(fn,delay)
*/
}
}
//要防抖的函數(shù)
function showTop(){
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條距頂部距離:'+scrollTop)
}
window.onscroll = debounce(showTop,1000)
節(jié)流
- 思考:
上述的防抖方法有效解決了短時間內(nèi)多次觸發(fā)的問題氓侧,但是又出現(xiàn)了一個問題,如果用戶一直在拖動滾動條导狡,一直觸發(fā)這個事件约巷,理論上這個處理函數(shù)永遠(yuǎn)不會執(zhí)行了。 - 實(shí)現(xiàn)效果
如果短時間內(nèi)大量觸發(fā)同一事件旱捧,那么在函數(shù)執(zhí)行一次后独郎,該函數(shù)在指定的事件期限內(nèi)不會再執(zhí)行,直至過了這段時間才生效枚赡。 - 實(shí)現(xiàn)
//利用setTimeout函數(shù)做簡單實(shí)現(xiàn)
function throttle(fn,delay){
// 狀態(tài)為valid表示當(dāng)前函數(shù)是否處于工作狀態(tài)
let valid = true
return function(){
if(!valid){
// valid為false則不執(zhí)行函數(shù)
return false
}
//valid當(dāng)前為true則將其設(shè)為false氓癌,并激活定時器
valid = false
//定時器在指定時間后會執(zhí)行處理函數(shù),并將valid置為true贫橙,可以準(zhǔn)備再次觸發(fā)函數(shù)
setTimeout(()=>{
fn()
valid = true
},delay)
}
}
//要節(jié)流的函數(shù)
function showTop(){
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條距頂部距離:'+scrollTop)
}
window.onscroll = throttle(showTop,1000)