含义
防抖节流都是限制函数的执行次数
- 防抖: 通过 setTimeout 的方式,在一定的时间间隔内,将多次触发转为一次触发。
- 节流: 减少一段时间的触发频率。
防抖 debouncer
三个参数(有默认值)
function debouncer(fn, delayTime = 1000, once = false)
- fn 执行的函数
- delayTime 延时时间
- once 前置 / 后置 触发执行的函数
html
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
function btnHandle(a, b, c) {
console.log("防抖函数", this, ...arguments);
}
$("#btn").on("click", debouncer(btnHandle, 1000, true));
$(window).scroll("click", debouncer(btnHandle, 2000, true));
//防抖
function debouncer(fn, delayTime = 1000, once = false) {
let timer = null;
return function () {
// 这个函数this指向没问题
//如果有计时器就清除
if (timer) clearTimeout(timer);
//第一次点击不延时 但是这个直到你不点然后延时结束 在点才会执行 所以once开启就为前置 关闭就为后置
if (once) {
//如果是第一次点击直接执行 这里第一次点击时timer为null 下面才会赋值timer
if (!timer) fn.apply(this, arguments);
//执行后 如果隔一段时间再点 还是认为 第一次执行 所以延时改一下timer
timer = setTimeout(() => {
timer = null;
}, delayTime);
return;
}
//再开定时器
timer = setTimeout(() => {
// fn(...arguments); //箭头函数所以可以arguments 要不然这个arguments取的是settimeout函数的arguments
// 但是要设置this指向 所以直接用apply
fn.apply(this, arguments); //因为用了箭头函数 this直接拿了外面的this
}, delayTime);
};
}
</script>
拆分防抖
后置触发
js
function btnHandle(a, b, c) {
console.log("防抖函数", this, ...arguments);
}
$("#btn").on("click", debouncer(btnHandle, 1000, true));
$(window).scroll("click", debouncer(btnHandle, 2000, true));
//触发多次 只会在停止触发后过段时间执行
function debouncer(fn, delayTime = 1000) {
let timer = null;
return function () {
// 这个函数this指向没问题
//如果有计时器就清除
if (timer) clearTimeout(timer);
//再开定时器
timer = setTimeout(() => {
// fn(...arguments); //箭头函数所以可以arguments 要不然这个arguments取的是settimeout函数的arguments
// 但是要设置this指向 所以直接用apply
fn.apply(this, arguments); //因为用了箭头函数 this直接拿了外面的this
}, delayTime);
};
}
前置触发
js
function btnHandle(a, b, c) {
console.log("防抖函数", this, ...arguments);
}
$("#btn").on("click", debouncer(btnHandle, 1000, true));
$(window).scroll("click", debouncer(btnHandle, 2000, true));
//触发多次 只会在第一次触发执行 必须停止一段时间 再点才执行
function debouncer(fn, delayTime = 1000) {
let timer = null;
return function () {
// 如果第一次触发直接执行 第一次timer是null
if (!timer) fn.apply(this.arguments);
// 清除定时器
clearInterval(timer);
// 开定时器
timer = setTimeout(() => {
timer = null;
}, delayTime);
};
}
ts中的防抖
ts中会不可以随便用this 需要这样写
ts
export default function debouncer(fn: Function, delayTime: number = 1000) {
let timer: any = null;
return function (this: any, ...arr: any) {
// 这个函数this指向没问题
console.log("this", this);
console.log("arr", arr);
//如果有计时器就清除
if (timer) clearTimeout(timer);
//再开定时器
timer = setTimeout(() => {
// fn(...arguments); //箭头函数所以可以arguments 要不然这个arguments取的是settimeout函数的arguments
// 但是要设置this指向 所以直接用apply
fn.apply(this, arr); //因为用了箭头函数 this直接拿了外面的this
}, delayTime);
};
}
-----------测试------------
function getOrder() {}
const newGetOrder = debouncer(getOrder, 400)
newGetOrder("search",123,3,312,33,123,321,3,3,32,3)
//打印结果为
this undefined
arr (11)>['search', 123, 3, 312, 33, 123, 321, 3, 3, 32, 3]
节流 throttle
setTimeout 方式
js
function throttle(fn, delayTime = 1000) {
//节流阀
let swi = true;
return function () {
//如果关闭状态就退出
if (!swi) return;
//没关闭的话先关闭
swi = false;
//再开定时器
setTimeout(() => {
fn.apply(this, arguments);
//开启节流阀
swi = true;
}, delayTime);
};
}
节流阀可以换为timer
ts
export default function throttle(fn: Function, delayTime: number = 1000) {
let timer: any = null;
return function (this: any, ...arr: any) {
if (timer) return;
fn.apply(this, arr);
timer = setTimeout(() => {
clearTimeout(timer); //这种是不行的 clearTimerout后timer还是有值
timer = null; //重新赋值timer
console.log(null);
}, delayTime);
};
}
时间戳方式
js
function throttle(fn, delayTime = 1000) {
let temp = 0;
return function () {
let sign = Date.now();
//当前时间和上次执行时间超过规定时间才执行
if (sign - temp > delayTime) {
fn.apply(this, arguments);
temp = sign;
}
};
}