应用场景浏览器
实际工做中,咱们常常性的会经过监听某些事件完成对应的需求,好比: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); } }