1.怎么理解防抖和节流
防抖:一定时间内(定时器延时间)用户频繁的去触发一个事件,只执行最后一次得触发
比如输入框的input事件,每输一个文字就会触发一次,这样频繁的触发会消耗性能。使用防抖后只会在你输入完成后才会触发
节流:控制触发事件的次数,控制多久能触发一次,分为首节流和尾节流
节流可理解为游戏中的技能,释放一个技能后会有技能CD,等CD事件结束才可以再次释放技能
首节流:使用时间戳实现,触发事件后能立即执行
尾节流:使用定时器实现,触发事件后,要经过延时才会执行
2.实现防抖
先说一下实现思路
首先要定义一个变量(timer)用来存放定时器id,触发事件后判断timer是否为空,为空就清除定时器,重新开始,定时器内执行业务代码并将timer改为空
代码:
<!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>
<input type="text">
</body>
<script>
let input = document.querySelector('input')
// 绑定input事件
input.oninput = debounce(inputValue, 1000)
// 封装防抖函数
function debounce (fn, delay) {
let timer = null
return function () {
// 当有定时器执行是timer不为null,清除定时器重新开始
if (timer !== null) {
clearTimeout(timer)
}
// 将定时器的返回值id赋值给timer
timer = setTimeout(() => {
fn.apply(this, arguments)
// 执行完业务代码后将timer赋值为null,防止进入上面的if判断
timer = null
}, delay)
}
}
// 业务代码
function inputValue (event) {
let value = event.target.value
if (value) {
console.log(value)
}
}
</script>
</html>
3.实现节流
首节流实现思路(时间戳):
1.定义一个变量用来存放旧的(lastTime)时间戳
2.获取最新的时间戳(newTime)
3.使用最新的时间戳(newTime)减去旧的时间戳(lastTime)如果大于设定的时间(delay)就可以再次执行,并将最新时间赋值给旧时间
<!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>
<style>
.box {
height: 2000px;
}
</style>
<body>
<div class="box"></div>
</body>
<script>
window.onscroll = throttle(throttleHandle, 2000)
// 封装首节流
function throttle (fn, delay) {
let lastTime = 0
return function () {
let newTime = new Date()
if (delay <= newTime - lastTime) {
fn.apply(this, arguments)
lastTime = newTime
}
}
}
// 业务逻辑代码
function throttleHandle () {
console.log('首节流');
}
</script>
</html>
尾节流实现方法 (定时器):
1.定义一个变量用来存放定时器ID(timer)
2.如果 !timer 为真就进入定时器并将定时器返回值赋值给 timer
3.定时器执行业务代码并将timer赋值为null
<!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>
<style>
.box {
height: 2000px;
}
</style>
<body>
<div class="box"></div>
</body>
<script>
window.onscroll = throttle(throttleHandle, 2000)
// 封装尾节流
function throttle (fn, delay) {
let timer = null
return function () {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
}
// 业务逻辑代码
function throttleHandle () {
console.log('尾节流');
}
</script>
</html>
首节流+尾节流实现
<!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>
<style>
.box {
height: 2000px;
}
</style>
<body>
<div class="box"></div>
</body>
<script>
window.onscroll = throttle(throttleHandle, 2000)
function throttle (fn, delay) {
let lastTime = 0
let timer = null
return function () {
let newTime = Date.now()
let remaining = delay - (newTime - lastTime)
clearTimeout(timer)
if (remaining <= 0) {
// 触发时间间隔大于设定时间(delay)
fn.apply(this, arguments)
lastTime = newTime
} else {
// 触发时间间隔小于设定时间(delay)
timer =setTimeout(() => {
fn.apply(this, arguments)
lastTime = newTime
}, remaining)
}
}
}
// 业务逻辑代码
function throttleHandle () {
console.log('首节流+尾节流');
}
</script>
</html>