1.防抖
使用场景 (事件多次触发只执行最后一次)
- 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
- 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
- 文本编辑器实时保存,当无任何更改操作一秒后进行保存
无论触发事件多少次,但一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,时间重新计算,n 秒后才执行,总之,就是要等你触发完事件 n 秒内不再触发事件,再执行。
<input type="text" id="input" placeholder="请输入内容" />
<script>
/*
1.当持续触发事件 (键盘一直输入),一定时间内没有再触发事件 (键盘抬起了),事件处理函数才会执行一次,
如果设定的时间来到之前 又一次触发了事件 就重新开始延时
2.存储timer变量,所有独立的执行函数都能访问到这个timer变量,而且现在这个timer变量
只创建了一次,是唯一的,我们只不过不断给timer赋值进行延时而已,每个清除延时就是
清除上一个定义的延时,相当于多个函数公用同一个外部变量
*/
function debounce(callback, delay) {
if (typeof callback !== 'function') { // 参数类型为函数
throw new TypeError('fn is not a function');
}
let timer;
return function () {
if (timer !== null) {
clearTimeout(timer);
}
timer = setTimeout(() => {
// 通过call让调用时的函数指向input输入框(apply也可以)
callback.call(this);
}, delay);
};
}
// 获取节点
let input = document.getElementById("input");
// 监听按键
input.oninput = debounce(function () {
console.log(this.value);
}, 1000);
//方式2
// 可以用来传入多个参数
function debounce(fun, delay) {
return function (...args) {
clearTimeout(fun.id);
fun.id = setTimeout(() => {
fun.call(this, ...args);
}, delay);
};
}
let inputb = document.getElementById("debounce");
let debounceAjax = debounce((content, arg, obj) => {
console.log(" content ", content);
console.log(" arg ", arg);
console.log(" obj ", obj);
}, 1000);
inputb.addEventListener("keyup", function (e) {
// 传入多个参数
debounceAjax(e.target.value, { x: 5, y: 10 }, { z: 5, k: 10 });
});
节流
使用场景
持续触发事件时,不会执行多次,每隔固定的时间执行一次, 触发停止时,过一段时间在执行逻辑代码
- scroll 事件,每隔一秒计算一次位置信息等
- 浏览器播放事件,每个一秒计算一次进度信息等
// 获取节点
let input = document.getElementById("input");
function throttle(callback, delay) {
let flag = true;
return function () {
if (flag) {
setTimeout(() => {
callback.call(this);
flag = true;
}, delay);
}
flag = false;
};
}
input.oninput = throttle(function () {
console.log(this.value);
}, 1000);
window.onscroll = throttle(function () {
console.log("hello");
}, 1000);