概念
防抖:连续调用后等待一段时间执行一次,如果等待时间内又重新触发,将重新等待一段时间执行
节流:连续调用,在指定时间段内内只执行一次
两者的目的都是减少触发的次数,保证性能和效率,区别在于业务场景和需求的不同。可以触发防抖和节流的事件有:onscroll、onmouseMove、onChange、onResize等。
具体怎么实现的还是看代码比较容易理解
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>防抖:多次调用后只执行一次</title>
</head>
<body style="height:1400px;">
<script>
'use strict'
function debounce(fn,delay){
var timer; //闭包保存局部变量
return function(...args) {
if(timer){
clearTimeout(timer)
}
timer = setTimeout(() => {
fn(...args);
timer = null;
},delay);
}
}
//处理函数
function mouseMove (event) {
let e = event || window.event;
console.log('移动的位置了:',e.clientX,e.clientY);
}
window.onmousemove = debounce(mouseMove,1000);
</script>
</body>
</html>
react hooks里的防抖
function useDebounce(fn, delay) {
const { current } = useRef(null);
//每次组件重新渲染,都会执行一遍所有的hooks,这样debounce高阶函数里面的timer就不能起到缓存的作用
//因此需要将定时器绑定到对应的DOM上,防止其他hooks误触发
return function (...args) {
if (current.timer) {
clearTimeout(current.timer);
}
current.timer = setTimeout(fn.apply(this,...args), delay);
}
}
需要注意的地方:
1.用闭包保存上一次调用的函数
2.闭包里需考虑this的指向和参数传递
3.执行完清除局部变量的引用,杜绝内存泄露
节流有两种处理方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>节流:指定时间间隔只执行一次</title>
</head>
<body style="height:1400px;">
<script>
'use strict'
//第一种:用定时器去处理时间间隔
function throttle(fn,delay){
let valid = true;
return function() {
if(!valid){
return false;
}
valid = false;
setTimeout(() => {
fn();
valid = true;
}, delay);
}
}
function showTop () {
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
window.onscroll = throttle(showTop,1000);
//第二种:用时间戳去处理时间间隔****************************************************************************************
function throttle1(fn,delay){
let startTime = new Date();//使用闭包,变量一直存在内存里
return function() {
let endTime = new Date();
if(endTime - startTime >= delay){
fn();
startTime = endTime;
}
}
}
function mouseMove (event) {
let e = event || window.event;
console.log('移动的位置了:',e.clientX,e.clientY);
}
window.onmousemove = throttle1(mouseMove,1000)
</script>
</body>
</html>
react hooks里面的节流
function useThrottle(fn, delay) {
const { current } = useRef(null);//用于防止其他hook导致的重新渲染
return function (...args) {
if (!current.timer) {
current.timer = setTimeout(() => {
delete current.timer;
}, delay);
fn(...args);
}
}
}