本文借鉴于 https://segmentfault.com/a/1190000018428170
防抖和节流是开发中经常遇到的需求,先看下 定义:
一、防抖
对于短时间内连续触发的事件(比如页面滚动事件),防抖的含义就是让某个时间期限(如1000毫秒)内,事件处理函数只执行一次
function debounce(fn,delay){
let timer = null //借助闭包
return function() {
if(timer){
clearTimeout(timer)
}
timer = setTimeout(fn,delay)
}
}
二、节流
类似控制阀门一样定期开放的函数,也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活
效果:如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效
1、使用 setTimeout 实现节流
function throttle(fn,delay){
let valid = true
return function() {
if(!valid){
//休息时间 暂不接客
return false
}
// 工作时间,执行函数并且在间隔期内把状态位设为无效
valid = false
setTimeout(() => {
fn()
valid = true;
}, delay)
}
}
/* 请注意,节流函数并不止上面这种实现方案,
例如可以完全不借助setTimeout,可以把状态位换成时间戳,然后利用时间戳差值是否大于指定间隔时间来做判定。
也可以直接将setTimeout的返回的标记当做判断条件-判断当前定时器是否存在,如果存在表示还在冷却,并且在执行fn之后消除定时器表示激活,原理都一样
*/
2、使用时间戳实现节流
function throttle(fn,delay) {
let time = 0
return function() {
if(Date.now() - time > delay) {
fn()
time = Date.now()
}
}
}
总结一些节流与防抖的应用场景:
-
搜索框input事件,例如要支持输入实时搜索可以使用节流方案(间隔一段时间就必须查询相关内容),或者实现输入间隔大于某个值(如500ms),就当做用户输入完成,然后开始搜索,具体使用哪种方案要看业务需求。
-
页面resize事件,常见于需要做页面适配的时候。需要根据最终呈现的页面情况进行dom渲染(这种情形一般是使用防抖,因为只需要判断最后一次的变化情况)
写了一大堆,在页面上试一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button onclick="throttle1()">节流</button>
<button onclick="debounce1()">防抖</button>
</body>
<script>
function fn() {
console.log("防抖");
}
function fn1() {
console.log("节流");
}
let debounce1 = debounce(fn, 500);
let throttle1 = throttle(fn1,500)
// function throttle(fn,delay) {
// let flag = true
// return function() {
// if(!flag) {
// return false
// }
// flag = false
// setTimeout(() => {
// fn()
// flag = true
// },delay)
// }
// }
function throttle(fn,delay) {
let time = 0
return function() {
if(Date.now() - time > delay) {
fn()
time = Date.now()
}
}
}
function debounce(fn, delay) {
let time = null;
return function () {
if (time) {
clearTimeout(time);
}
time = setTimeout(fn, delay);
};
}
</script>
</html>