防抖
所谓防抖,就是指触发事件后,函数在 n 秒后才执行函数,如果在 n 秒内又触发了事件,则会重新计算函数执行时间
简单的说,当一个函数连续触发,只执行最后一次。
函数防抖一般用在什么情况之下呢?一般用在:连续的事件只需触发一次回调的场合。
具体有:
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求;
- 用户名、手机号、邮箱输入验证;
- 浏览器窗口大小改变后,只需窗口调整完后,再执行resize事件中的代码,防止重复渲染。
代码实现:
<div class="box"></div>
<style>
.box {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
防抖函数封装:
// fn是要调用的函数,wait是等待的时间,immediate是第一次是否立即执行
function debounce(fn, wait, immediate) {
let timerID = null;
// 返回一个闭包函数,用闭包保存timerID确保其不会销毁,重复点击会清理上一次的定时器
return function () {
const context = this; // this依然指向原来的函数
// console.log(this); // this指向触发事件的对象<div class="box"></div>
const args = [...arguments]; // 不同的函数会有不同的参数传入,保存事件参数
// console.log(arguments); // Arguments[MouseEvent, callee: ƒ, Symbol(Symbol.iterator): ƒ]
if (timerID) clearTimeout(timerID); // 调用一次 就清除上一次的定时器
// 如果第一次需要立即执行
if (immediate) {
const callNow = !timerID; // 当第一次触发事件时,timerID为null,则callNow为true
timerID = setTimeout(() => {
timerID = null; // 相当于清空定时器
}, wait);
// 没有定时器id,则执行函数
if (callNow) {
fn.apply(context, args);
}
}
// 第一次不需要立即执行 有定时器id,则防抖延迟
else {
timerID = setTimeout(() => {
fn.apply(context, args);
}, wait);
}
};
}
使用:
const box = document.querySelector('.box');
// 要执行的函数
const doSomeThing = function (e) {
// console.log(this);
// console.log(e); // e是[MouseEvent]事件对象
// 要执行的事情:比如发送ajax请求···
console.log('啦啦');
};
box.onmousemove = debounce(doSomeThing, 500, true);
节流
节流就是限制一个函数在一段时间内只能执行一次,过了这段时间,在下一段时间又可以执行一次。
连续触发事件,但是在 n 秒中只执行一次函数。 节流会稀释函数的执行频率。
应用场景:
- 输入框的联想,可以限定用户在输入时,只在每两秒钟响应一次联想。
- 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
- 表单验证
- 按钮提交事件
<input type="text" id="input">
封装节流函数:
function throttle(fn, wait) {
let timerID = null;
let prev = new Date().getTime(); // 上一次触发的时间戳
// 返回闭包函数
return function () {
const context = this; // 保存this
// console.log(this); // this是触发事件对象<input type="text" id="input">
const args = [...arguments]; // 保存事件参数
// console.log(arguments); // Arguments [KeyboardEvent, callee: ƒ, Symbol(Symbol.iterator): ƒ]
let now = new Date().getTime(); // 现在触发的时间戳
// 清除定时器
clearTimeout(timerID);
// 如果两次间隔时间>设定的等待时间,则执行事件处理函数fn,并且把这次调用的时间设置为上一次执行时间
if (now - prev >= wait) {
fn.apply(context, args);
prev = new Date().getTime();
} else {
// 否则,过了剩余时间,执行最后一次fn
timerID = setTimeout(() => {
fn.apply(context, args);
}, wait);
}
};
}
使用:
const input = document.querySelector('#input');
function check() {
let val = this.value;
if (val.length < 6) {
console.log('长度不够');
} else {
console.log('验证通过');
}
};
input.onkeyup = throttle(check, 1000);