防抖(Debounce)
概念
防抖,指的是在触发事件后的一定时间内(例如 3秒)函数只能执行一次,如果在这段时间(3秒)内再次触发事件,则会重新计算函数执行的时间。
为了更好的理解,在这边举个公交车的例子:公交车上,只要乘客不断地刷卡,司机师傅就不能开,等乘客都上车了,再等待的时间内没有人上车,才会开车走。如果在wait的时间内又有人上车,那就重新开始一个等待时间
防抖函数分类
- 非立即执行
- 立即执行
非立即执行版
就是在触发事件后不立即执行,而是在一定的等待时间后执行如果在这段时间内又触发事件,就重新计算执行时间。
/**
* @fn : 要执行的函数
* @delay : 执行执行函数的时间间隔
*/
// 输入完毕等待2秒后再可以查询(延迟执行)
function debounce (fn, delay=2000) {
let timer; // 定时器
return function (...args) {
let _this = this; // 绑定函数执行时的this绑定
timer && clearTimeout(timer); // 当函数再次执行的时候,清楚定时器,让定时器重新开始计时
timer = setTimeout (() => {
// 执行传入的函数
fn.apply (_this, args); // args是执行函数传入进来的参数
}, delay)
}
}
立即执行版
// 输入完毕后立即查询,过2秒后才能再查询(立即执行)
function debounce (fn, delay=2000) {
let timer;
return function (...args) {
let _this = this
timer && clearTimeout(timer);
let callNow = !timer;
timer = setTimeout (() => {
timer = null;
}, delay);
if (callNow) {
fn.apply(_this, args)
}
}
}
例子:
<input type="text" id="text">
let ipt = document.getElementById('text')
ipt.addEventListener('input', function(){
let val = this.value
handle(val)
})
let handle = debounce(handleSendPhone,2000);
// handleSendPhone就是要等待执行的函数
function handleSendPhone (val) {
ajaxRequest({
user: val
}).then((res)=>{
console.log(res)
})
}
// 模拟请求的数据
let datas = ['aaa','bbb','ccc','ddd']
function ajaxRequest({
user
}) {
return new Promise((resolve, reject) => {
let res = datas.includes(user) ? '正确' : '失败'
resolve(res)
})
}
两种都兼容的写法
/**
* @fn : 要执行的函数
* @delay : 执行执行函数的时间间隔
* @immediate: true 立即执行 false 非立即执行
*/
function debounce (fn, delay, immediate=false) {
let timer;
return function (...args) {
let _this = this
timer && clearTimeout(timer)
if (immediate) {
let callNow = !timer
if (callNow) {
fn.apply(_this,args)
}
timer = setTimeout(() => {
timer = null
},delay)
} else {
// timer 一定要赋值
timer = setTimerout(() => {
fn.apply(_this,args)
},delay)
}
}
}
节流(throttle)
概念
节流,指的是某个函数在一定时间间隔内(例如3秒)只执行一次,在这3秒内又调用请求会无视,也不会延长时间间隔。
例子
/**
* @fn : 要执行的函数
* @delay : 时间间隔
* @ return : 节流函数
*/
function throttle (fn, delay) {
let timer;
let prevTime; // 记录上一次执行的时间
return function (...args) {
let _this = this
let currTime = Date.now(); // 获取当前时间戳
`也可以这样获取 let currtime = +new Date()`
if (!prevTime) {
prevTime = currTime;
} // 第一次执行时,prevTime赋值为当前时间
timer && clearTimeout(timer); // 每次都清除定时器,保证定时器只是在最后一次执行
if (currTime - preTime > delay) { // 如果为true,则表示两次执行函数的时间间隔为delay.
prevTime = currTime; // 重置上次记录的时间
fn.apply(_this, args); // 执行函数,发送请求
} else {
timer = setTimeout(() => {
prevTime = Date.now();
fn.apply(_this, args);
}, delay)
}
}
}
总结
- 防抖和节流在一定程度上相似,都是为了节省资源,提升用户的体验。
- 防抖是在函数触发后延迟执行,在延迟时间内再次触发,会重新计算执行时间
- 节流是在函数连续点击时,在规定的时间内只执行一次。
最后
如果文章中有错误,请务必指出,万分感谢。