應用場景瀏覽器
實際工做中,咱們常常性的會經過監聽某些事件完成對應的需求,好比:app
常規實現,以監聽 scroll 事件爲例函數
咱們先來看一下scroll事件的觸發頻率oop
window.onscroll = function () { //滾動條位置 let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滾動條位置:' + scrollTop); }
效果以下:性能
從效果上,咱們能夠看到,在頁面滾動的時候,會在短期內觸發屢次綁定事件。優化
咱們知道DOM操做是很耗費性能的,若是在監聽中,作了一些DOM操做,那無疑會給瀏覽器形成大量性能損失。this
下面咱們進入主題,一塊兒來探究,如何對此進行優化。spa
函數防抖3d
定義:屢次觸發事件後,事件處理函數只執行一次,而且是在觸發操做結束時執行。code
原理:對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。
var timer; window.onscroll = function (e) { //防抖,當給timer賦值後,滾動又清空,直到中止滾動,執行timer函數 if(timer){ clearTimeout(timer) } timer = setTimeout(function(){ //執行事件函數 addLiScroll();
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)
函數節流
定義:觸發函數事件後,短期間隔內沒法連續調用,只有上一次函數執行後,過了規定的時間間隔,才能進行下一次的函數調用。
原理:對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。
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); } }
防抖函數的封裝使用
/** * 節流函數 * @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)
封裝簡便的寫法
var time; window.onscroll = function (e) { //節流, 每隔多久執行一次 if(!time){ time = setTimeout(() => { //執行的事件 addLiScroll(); time = undefined; }, 1000); } }