什么是防抖函数
概念:
函数防抖(debounce)是指在一定时间内,在动作被连续频繁触发的情况下,动作只会被执行一次,也就是说当调用动作过n毫秒后,才会执行该动作
原理
- debounce 函数在主线程顺序执行时已经被调用,传入的参数一个是真正想在事件触发执行的事件处理函数
- 另一个参数是事件触发的间隔时间,间隔时间内再次触发事件,则重新计时,类似于罚你 5 分钟内不准说话,时间到后就可以开始说话,如果 5 分钟内说话了,则再罚你 5 分钟内不准说话,以此类推~
应用场景
在用户和前端页面的交互过程中,很多操作的触发频率非常高,比如鼠标移动 mousemove 事件, 滚动条滑动 scroll 事件, 输入框 input 事件, 键盘 keyup 事件,浏览器窗口 resize 事件。
function debounce(fn, delay) {
// 参数为传入的事件处理函数和间隔时间
var interval = delay || 1000;
// 闭包保存的 timer 变量,会常驻内存
var timer = null;
//返回的匿名函数是事件的回调函数,在事件触发时执行,参数为 DOM 事件对象(event)
return function() {
var args= arguments;
// 事件的回调函数中,this 指向事件的绑定的 DOM 元素对象(HTMLElement)
var context = this;
//如果事件回调函数中存在定时器,则清空上次定时器,重新计时。如果间隔时间到后,处理函数自然就被执行了。
clearTimeout(timer);
//定时器时间到后,执行事件真正的处理函数 handler
timer = setTimeout(function() {
//执行的事件处理函数(handler),需要把调用对象 this 和事件对象 传递过去,就像没被debounce处理过一样
fn.apply(context, args);
}, interval);
};
}实例
var inputEl = document.getElementById("nwdInput");
// debouce 函数执行了,返回一个函数,该函数为事件的回调函数
inputEl.oninput = debounce(ajax);
// 事件真正的处理函数(handler),参数是回调函数传递过来的。
// 常见场景就是边输入查询关键字,边请求查询数据,比如百度的首页搜索
function ajax(event) {
console.log("HTTP 异步请求:", event.target.value);
}
什么是节流函数
概念
节流函数(throttle)就是让事件处理函数(handler)在大于等于执行周期时才能执行,周期之内不执行,即函数节流是间隔时间执行,不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数。
原理
节流函数可以用时间戳和定时器两种方式进行处理。当我触发一个事件时,先setTimout让这个事件延迟一会再执行,如果在这个时间间隔内又触发了事件,那我们就clear掉原来的定时器,再setTimeout一个新的定时器延迟一会执行
应用场景
- 页面滚动和改变大小时需要进行业务处理,比如判断是否滑到底部,然后进行懒加载数据。
- 按钮被高频率地点击时,比如游戏和抢购网站。
时间戳方式实现:
function throttle(fn, delay) {
var delay = delay || 1000;
//初始化一个时间,也作为高频率事件判断事件间隔的变量,通过闭包进行保存。
var previous = new Date().getTime();
return function() {
var context = this;
var args = arguments;
var now = new Date().getTime();
//如果本次触发和上次触发的时间间隔超过设定的时间 就执行事件处理函数 (eventHandler)
if (now - previous >= delay) {
fn.apply(context, args);
//然后将本次的触发时间,作为下次触发事件的参考时间。
previous = now;
}
};
}实例
var count = 0;
window.onload = function() {
window.onscroll = throttle(eventHandler, 1000);
};
function eventHandler(e) {
var containerEl = document.getElementById("container");
containerEl.innerHTML = count;
count++;
}
定时器方式实现
function throttle(fn, delay) {
var delay = delay || 1000;
var timer = null;
return function() {
var args = arguments;
var context = this;
if (!timer) {
timer = setTimeout(function() {
clearTimeout(timer);
timer = null;
fn.apply(context, args);
}, delay);
}
};
}两种方式对比
对比时间戳和定时器两种方式,效果上的区别主要在于: 事件戳方式会立即执行,定时器会在事件触发后延迟执行,而且事件停止触发后还会再延迟执行一次。 具体选择哪种方式取决于使用场景