防抖和节流
防抖函数
防抖函数的概念:
- 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间
- 当事件频繁的被触发时,函数的触发会被频繁的推迟
- 只有等待了一段时间后,没有事件继续触发,函数才会执行
防抖函数的封装
实现的功能:
- 绑定正确的this,event对象
- 控制第一次立即执行,后面得执行防抖
- 实现取消操作
- 获取执行函数的返回值
js
function debounce(fn, delay, immediate = false, ) {
let timer = null;
//定义内部变量来控制是否第一个立即执行
let isInvoke = false;
const _debounce = function (...args) {
//返回一个Promise用来处理函数的返回值
return new Promise((resolve) => {
if (timer) clearTimeout(timer);
//判断是否立即执行
if (immediate && !isInvoke) {
let result = fn.apply(this, args);
//promise返回 函数的返回值
resolve(result);
isInvoke = true;
} else {
timer = setTimeout(() => {
let result = fn.apply(this, args);
//promise返回 函数的返回值
resolve(result);
isInvoke = false;
timer = null;
}, delay);
}
});
};
//取消请求的发送
_debounce.cancel = function () {
if (timer) clearTimeout(timer);
timer = null;
isInvoke = false;
console.log("取消成功!");
};
return _debounce;
}
节流函数
节流的概念:
- 当事件触发时,会执行这个事件的响应函数
- 如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数
- 不管在这个中间有多少次触发这个事件,执行函数的频繁总是固定的
函数的实现:在interval时间内,每次触发都创建一个定时器,创建之前先清除上一个定时器
js
function throttle(
fn,
interval,
options = {
leading: true,
trailing: false,
},
resultCallback
) {
let timer = null;
//leading第一次是否触发,trailing最后一次是否触发
const {leading, trailing} = options;
let lastTime = 0;
const _throttel = function (...args) {
//在一段时间内最后一次触发的时间
let nowTime = new Date().getTime();
//如果leading=true 并且 lastTime = 0时,使第一次不触发
if (!leading && !lastTime) lastTime = nowTime;
//需要等待多少时间执行
let remainTime = interval - (nowTime - lastTime);
if (remainTime <= 0) {
clearTimeout(timer);
const result = fn.apply(this, args);
if (resultCallback) resultCallback(result);
lastTime = nowTime;
} else {
if (trailing) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
const result = fn.apply(this, args);
if (resultCallback) resultCallback(result);
lastTime = new Date().getTime();
timer = null;
}, remainTime);
}
}
};
_throttel.cancel = function () {
if (timer) clearTimeout(timer);
timer = null;
lastTime = 0;
};
return _throttel;
}
函数的实现2:在interval时间内,只创建一次定时器
js
function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing, resultCallback } = options
let lastTime = 0
let timer = null
// 2.事件触发时, 真正执行的函数
const _throttle = function(...args) {
return new Promise((resolve, reject) => {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
// 第一次不触发
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长时间需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
// 2.3.真正触发函数
const result = fn.apply(this, args)
resolve(result)
// 2.4.保留上次触发的时间
lastTime = nowTime
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
lastTime = !leading ? 0: new Date().getTime()
const result = fn.apply(this, args)
resolve(result)
}, remainTime)
}
})
}
_throttle.cancel = function() {
if(timer) clearTimeout(timer)
timer = null
lastTime = 0
}
return _throttle
}
其他库
underscore: https://underscorejs.org/
loadsh:https://www.lodashjs.com/ 使用人数较多