在事件触发后的指定时间之后,再去执行真正需要执行的函数,如果在该时间之内事件又被触发,则重新开始计时。
常见的应用场景:
1. 滚动事件触发
2. 搜索框输入查询
3. 表单验证
4. 按钮提交事件
5. 浏览器窗口缩放
以下是代码实现:
function debounce(func, time, immediate) {
// 用来获取返回值
let timer, result;
let debounced = function () {
// 保存当前指向
let that = this;
// 获取函数的参数
let args = arguments;
// 清除当前定时器
clearTimeout(timer);
// 立即执行
if (immediate) {
let callNow = !timer;
// 指定时间内不再执行
timer = setTimeout(function () {
timer = null;
}, time);
if (callNow){
result = func.call(that, ...args);
};
// 不立即执行
} else {
// 指定时间后触发函数
timer = setTimeout(function () {
// 改变函数内部指向,并传递参数
func.call(that, ...args);
}, time);
};
return result;
};
// 取消函数
debounced.cancel = function () {
// 清除定时器
clearTimeout(timer);
// 定时器置空
timer = null;
};
// 返回防抖函数
return debounced;
}
在指定时间内触发多次函数的话,只有一次是可被执行的,下一次执行只能等到下一个周期里。
常见的应用场景:
1. DOM元素的拖拽功能实现
2. 射击游戏
3. 计算鼠标的移动距离
4. 监听滚动事件
截流函数根据是否立即执行,操作完成后是否还会执行一次,分为三种情况:
1. 用时间戳来实现。第一次立即执行,操作完成后不再执行。
function throttle(func, time) {
let that, args;
let old = 0;
return function () {
// 获取当前的时间戳
let now = new Date().valueOf();
// 保存当前指向
that = this;
// 获取函数的参数
args = arguments;
if (now - old > time) {
// 改变函数内部指向,并传递参数
func.apply(that, args);
// 更新旧时间戳
old = now;
}
}
};
2. 用定时器实现节流函数。第一次延时执行,操作完成后还会执行一次。
function throttle(func, time) {
let that, args, timer;
return function () {
// 保存当前指向
that = this;
// 获取函数的参数
args = arguments;
if (!timer) {
timer = setTimeout(function () {
timer = null;
func.apply(that, args);
}, time);
}
}
};
3. 用时间戳与定时器结合实现截流函数。第一次立即执行,操作完成后还会执行一次。
function throttle(func, time) {
let that, args, timer;
let old = 0;
return function () {
// 保存指向
that = this;
args = arguments;
let now = new Date().valueOf();
if (now - old > time) {
if (timer) {
clearTimeout(timer);
timer = null;
}
func.apply(that, args);
old = now;
};
if (!timer) {
timer = setTimeout(function () {
// 更新最新的时间戳
old = new Date().valueOf();
timer = null;
func.apply(that,args);
}, time);
}
}
}
最终版,用时间戳与定时器结合实现截流函数。根据参数来决定开始是否立即执行,结束后是否还会执行。
function throttle(func, time, options) {
let that, args, timer;
// 设置初始时间戳
let old = 0;
// 如果没有该参数,置为空对象
if(!options){options = {}};
return function () {
that = this;
args = arguments;
// 获取初始的时间戳
let now = new Date().valueOf();
// leading为false表示不立即执行
if (options.leading === false && !old) {
old = now;
};
if (now - old > time) {
if (timer) {
clearTimeout(timer);
timer = null;
}
func.apply(that, args);
old = now;
};
// trailing为true表示最后一次会被执行
if (!timer && options.trailing==true) {
timer = setTimeout(function () {
// 更新最新的时间戳
old = new Date().valueOf();
timer = null;
func.apply(that,args);
}, time);
}
}
}