JavaScript函数防抖和节流

概述
【JavaScript函数防抖和节流】函数防抖是指将多次触发合并成一次执行,一般情况下都是合并到最后一次触发执行。函数节流是指在一段时间内执行一次,有可能触发在开始位置,也有可能在这段时间结束位置。其目的都是减少系统消耗,缩减执行频率,提升系统整体执行效率。
浏览器兼容事件处理程序

const EventUtil = { register(el, type, handler) {//事件注册 if (el.addEventListener) { el.addEventListener(type, handler, false); //false事件冒泡阶段触发 } else if (el.attachEvent) { el.attachEvent(`on${type}`, handler); } else { el[`on${type}`] = handler; } }, remove(el, type, handler) {//删除事件回调 if (el.removeEventListener) { el.removeEventListener(type, handler, false); } else if (el.detachEvent) { el.detachEvent(`on${type}`, handler); } else { el[`on${type}`] = null; } } }

函数防抖Debounce
// 加入要监听页面鼠标滚动事件 // 正常绑定 const handler = function (e) { console.log("scroll"); }//事件触发后执行的代码 EventUtil.register(window, "scroll", handler); //注册事件 //控制台会不停的打印 scroll ,这样的话触发太频繁了// 防抖写法,设置定时器,丢弃原先触发,只执行最后一次触发,使触发不这么频繁。重点在于最后一次 const debounce = (handler, delay) => {// 设置只在触发后delay时间内没有再次触发该事件才执行handler let timer = null; // 保存一个计时器 return event => { clearTimeout(timer); //如果再次触发,先取消上次的计时器 timer = setTimeout(_ => handler(event), delay); } } EventUtil.register(window, "scroll", debounce(handler, 2000));

函数节流Throttle
// 所有的触发中,从计时器开始一定时间后(内)才执行一次,执行后重新计时。重点在于时间段内 const throttle = (handler, delay) => { let startTime = new Date().getTime(); return function () { const currentTime = new Date().getTime(); if (currentTime - startTime > delay) { startTime = new Date().getTime(); handler.apply(this, arguments); //这里绑定this } } }

可以看出,防抖和节流都会丢弃一些触发,但是有些关键触发也被丢弃了。比如在防抖中,如果该事件一直触发,可能存在回调函数永远不能被执行的情况,而在节流(上文中的那种写法)中,如果过delay设置的2s,当我在1s的时间内不停触发,而2s后再也不触发,也会造成回调函数从不调用的情况。所以需要将防抖和节流相结合,拦截关键触发点,调用回调函数。
函数防抖和节流组合
const DebounceThrottle = (handler, delay) => { let startTime = new Date().getTime(); let timer = null; return function () { let currentTime = new Date().getTime(); if (currentTime - startTime > delay) {// 节流 (如果时间段到了,则执行回调) clearTimeout(timer); startTime = new Date().getTime(); handler.apply(this, arguments); } else {// 防抖 (时间端没有到,记录最后一次,delay后调用回调) clearTimeout(timer); timer = setTimeout(_ => { startTime = new Date().getTime(); handler.apply(this, arguments); }, delay); } } }

    推荐阅读