1、先看個栗子
在很多網(wǎng)站中都有這樣一個功能名斟,在頁面顯示一個按鈕,用于返回頁面的頂部魄眉,這個按鈕只會在頁面滾動到一定位置的時候出現(xiàn)砰盐,如:
這個功能的核心內(nèi)容是----監(jiān)聽瀏覽器的滾動事件,返回當前滾動條與頂部之間的距離
具體的代碼如下所示:
function show_scrollPosition(){
var scrollPosition = document.body.scrollTop || document.documentElement.scrollTop;
console.log("當前滾動條位置為:",scrollPosition);
}
window.onscroll = show_scrollPosition
運行時(在chrome中杆融,選中滾動條楞卡,點擊一次鍵盤向下的方向鍵 ↓ )的結(jié)果如下所示:
在上圖中我們可以看到,這個事件的執(zhí)行頻率很高,非常消耗瀏覽器的性能蒋腮,在實際的運行中我們并不需要這么高頻率的執(zhí)行反饋淘捡。
為了避免這種場景,常見的優(yōu)化方式有:防抖和節(jié)流
2池摧、防抖(debounce)
JS防抖的基本思路是:規(guī)定一個期限時間焦除,在首次觸發(fā)事件時,不立即執(zhí)行回調(diào)函數(shù)作彤,而是在期限時間后再執(zhí)行膘魄,如果期限時間內(nèi)回調(diào)函數(shù)被重復(fù)執(zhí)行,則期限時間重新計時竭讳。
在這里要用到setTimeOut()函數(shù)创葡,判斷期限值范圍內(nèi)該執(zhí)行函數(shù)是否執(zhí)行過,則需要一個變量來保存執(zhí)行的結(jié)果绢慢。代碼實現(xiàn)如下所示:
/*
*fn --> 需要防抖的函數(shù)灿渴;
*delaytime --> 毫秒數(shù),防抖所需期限值胰舆;
*/
function debounce(fn,delaytime){
let timer = null
return function(){
if(timer){
clearTimeout(timer) //進入這里說明當前存在一個執(zhí)行過程骚露,并且同時又執(zhí)行了一個相同事件,故取消當前的執(zhí)行過程
}
timer = setTimeout(fn,delaytime)
}
}
function show_scrollPosition(){
var scrollPosition = document.body.scrollTop || document.documentElement.scrollTop;
console.log("當前滾動條位置為:",scrollPosition);
}
window.onscroll = debounce(show_scrollPosition,1000)
運行結(jié)果顯示缚窿,當前滾動停止1s后棘幸,才會打印當前的滾動條位置,而且每次值打印當前的位置倦零。
防抖的缺點
由上述的例子可以看出防抖的缺點在于误续,事件執(zhí)行完期限值范圍內(nèi)沒有重復(fù)觸發(fā)事件,才能再次執(zhí)行該回調(diào)函數(shù)光绕,若是期限范圍內(nèi)女嘲,不停的觸發(fā)該事件,則回調(diào)函數(shù)不會執(zhí)行诞帐,比如一直按著鍵盤的向下方向鍵欣尼,則一直不會打印出當前的滾動距離。
防抖的應(yīng)用場景
(1)用戶在輸入框中輸入一串字符停蕉,只會在最后一次輸入完成后再去執(zhí)行查詢ajax請求愕鼓,這樣可以有效減少請求的次數(shù),節(jié)約請求資源慧起。
(2)window的scroll菇晃、resize事件,不斷地滾動蚓挤、或調(diào)整瀏覽器窗口大小時觸發(fā)的對應(yīng)事件磺送,可以允許其只觸發(fā)一次驻子。
3、節(jié)流(throttle)
JS中節(jié)流的基本思路是:規(guī)定一個期限時間估灿,在該時間內(nèi)崇呵,觸發(fā)事件的回調(diào)函數(shù)只能執(zhí)行一次,如果期限時間內(nèi)回調(diào)函數(shù)被多次觸發(fā)馅袁,則只有一次能生效域慷。
代碼實現(xiàn)過程如下所示:
function throttle(fn, delay) {
let last_time
let timer = null
return function () {
let cur_time = new Date().getTime()
if (last_time && cur_time < last_time + delay) { //若為真,則表示上次執(zhí)行過汗销,且在期限值范圍內(nèi)
clearTimeout(timer)
timer = setTimeout(() => {
fn();
last_time = cur_time
}, delay)
} else {
last_time = cur_time;
fn();
}
}
}
function show_scrollPosition() {
var scrollPosition = document.body.scrollTop || document.documentElement.scrollTop;
console.log("當前滾動條位置為:", scrollPosition);
}
window.onscroll = throttle(show_scrollPosition, 1000)
節(jié)流的道理其實就是讓函數(shù)執(zhí)行一次后犹褒,在某個時間段內(nèi)暫時失效,過了這個時間段后再重新激活弛针。
節(jié)流的應(yīng)用場景
(1)在頁面無限加載的情況下叠骑,需要用戶再滾動頁面時,每隔一定時間發(fā)起一次ajax請求削茁,而不是再用戶停下滾動時再去請求數(shù)據(jù)座云;
(2)監(jiān)聽滾動事件,比如是否滑倒底部自動加載更多付材,則用節(jié)流來判斷;