應用場景
瀏覽器
實際工做中,咱們常常性的會經過監聽某些事件完成對應的需求,好比:app
常規實現,以監聽 scroll 事件爲例
函數
咱們先來看一下scroll事件的觸發頻率
oop
window.onscroll = function () {
//滾動條位置
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條位置:' + scrollTop);
}
效果以下:性能
從效果上,咱們能夠看到,在頁面滾動的時候,會在短期內觸發屢次綁定事件。優化
咱們知道DOM操做是很耗費性能的,若是在監聽中,作了一些DOM操做,那無疑會給瀏覽器形成大量性能損失。this
下面咱們進入主題,一塊兒來探究,如何對此進行優化。spa
函數防抖
code
定義:屢次觸發事件後,事件處理函數只執行一次,而且是在觸發操做結束時執行。blog
原理:對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。
scroll 的一個簡單例子
let timer;
window.onscroll = function () {
if(timer){
clearTimeout(timer)
}
timer = setTimeout(function () {
//滾動條位置
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條位置:' + scrollTop);
timer = undefined;
},200)
}
效果以下:滾動結束觸發事件
防抖函數的封裝使用
/**
* 防抖函數
* @param method 事件觸發的操做
* @param delay 多少毫秒內連續觸發事件,不會執行
* @returns {Function}
*/
function debounce(method,delay) {
let timer = null;
return function () {
let self = this,
args = arguments;
timer && clearTimeout(timer);
timer = setTimeout(function () {
method.apply(self,args);
},delay);
}
}
window.onscroll = debounce(function () {
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條位置:' + scrollTop);
},200)
函數防抖的適用性:
經過上面的例子,咱們知道咱們能夠經過函數防抖,解決了屢次觸發事件時的性能問題。
好比,咱們在監聽滾動條位置,控制是否顯示返回頂部按鈕時,就能夠將防抖函數應用其中。
但依然有些功能並不適用:
當咱們作圖片懶加載(lazyload)時,須要經過滾動位置,實時顯示圖片時,若是使用防抖函數,懶加載(lazyload)函數將會不斷被延時,
只有停下來的時候纔會被執行,對於這種須要實時觸發事件的狀況,就顯得不是很友好了。
下面開始介紹函數節流,經過設定時間片,控制事件函數間斷性的觸發。
函數節流
定義:觸發函數事件後,短期間隔內沒法連續調用,只有上一次函數執行後,過了規定的時間間隔,才能進行下一次的函數調用。
原理:對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。
scroll 的一個簡單例子
let startTime = Date.now(); //開始時間
let time = 500; //間隔時間
let timer;
window.onscroll = function throttle(){
let currentTime = Date.now();
if(currentTime - startTime >= time){
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條位置:' + scrollTop);
startTime = currentTime;
}else{
clearTimeout(timer);
timer = setTimeout(function () {
throttle()
}, 50);
}
}
效果以下:每隔500毫秒觸發一次事件
防抖函數的封裝使用
/**
* 節流函數
* @param method 事件觸發的操做
* @param mustRunDelay 間隔多少毫秒須要觸發一次事件
*/
function throttle(method, mustRunDelay) {
let timer,
args = arguments,
start;
return function loop() {
let self = this;
let now = Date.now();
if(!start){
start = now;
}
if(timer){
clearTimeout(timer);
}
if(now - start >= mustRunDelay){
method.apply(self, args);
start = now;
}else {
timer = setTimeout(function () {
loop.apply(self, args);
}, 50);
}
}
}
window.onscroll = throttle(function () {
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條位置:' + scrollTop);
},800)
文中若是出現錯誤,但願小夥伴們能夠諒解,更但願能夠給予指正