JS 手写函数防抖与函数节流
函数防抖
概念
函数防抖是在事件被触发 n 秒后再执行回调,如果在 n 秒内又被触发,则重新计时。 函数防抖多用于 input 输入框。
实现过程:
- 箭头函数的 this 继承自父级上下文,这里指向触发事件的目标元素
- 事件被触发时,传入 event 对象
- 传入 leading 参数,判断是否可以立即执行回调函数,不必要等到事件停止触发后才开始执行
- 回调函数可以有返回值,需要返回执行结果
实现
// fn->事件触发的回调,wait->防抖时间范围,leading->回调函数是否立即执行标志位
const debounce = (fn, wait = 300, leading = true) => {
let timerId, result;
return function (...args) {
timerId && clearTimeout(timerId);
// 如果是立即执行的话,第一次触发事件回调函数就会执行,后面在wiat时间内再次触发则不再执行回调函数
if (leading) {
if (!timerId) result = fn.apply(this, args);
// 在等待wait时间之后才能再次触发回调函数
timerId = setTimeout(() => (timerId = null), wait);
} else {
// 如果不是立即执行函数,则是再次触发时清空定时器重新计时,等到wait时间之后再执行回调函数
timerId = setTimeout(() => (result = fn.apply(this, args)), wait);
}
return result;
};
};
函数节流
概念
函数节流是指连续触发事件,但是在 n 秒中只执行一次函数,适合应用于动画相关的场景。
实现
定时器版本
const throttle = (fn, wait = 300) => {
let timerId;
return function (...args) {
if (!timerId) {
timerId = setTimeout(() => {
timerId = null;
return fn.apply(this, args);
}, wait);
}
};
};
// test执行一次大概要10ms左右
function test(name) {
if (name) {
console.log(name);
} else {
console.log("no-name");
}
}
const newTest = throttle(test);
// 300ms内出发多次,函数只会执行第一次
newTest("foo");
newTest("bar");
时间戳版本
const throttle = (fn, wait = 300) => {
let prev = 0;
return function (...args) {
let now = +new Date();
if (now - prev >= wait) {
prev = now;
return fn.apply(this, args);
}
};
};
// test执行一次大概要10ms左右
function test(name) {
if (name) {
console.log(name);
} else {
console.log("no-name");
}
}
const newTest = throttle(test);
// 300ms内出发多次,函数只会执行第一次
newTest("foo");
newTest("bar");
时间戳版本和定时器版本节流函数的区别:
定时器+时间戳版本
// leading:false 表示禁用第一次执行
// trailing: false 表示禁用停止触发的回调
const throttle = (
fn,
wait = 300,
{
// 参数解构赋值
leading = true,
trailing = true,
} = {}
) => {
let prev = 0;
let timerId;
const later = function (args) {
timerId && clearTimeout(timerId);
timerId = setTimeout(() => {
timerId = null;
fn.apply(this, args);
}, wait);
};
return function (...args) {
let now = +new Date();
if (!leading) return later(args);
if (now - prev > wait) {
fn.apply(this, args);
prev = now;
} else if (trailing) {
later(args);
}
};
};