声明:纯属小白个人理解,如有不对欢迎批评指正。
目录
示例完整代码Demo.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<button onclick="btn()">回城(需要5秒)</button>
<button onclick="btn2()">技能(2秒冷却)</button>
</html>
<script>
// 防抖
let btn = debounce(goHome)
function goHome() {
console.log("成功回到泉水~~")
}
function debounce(fun) {
let timer = null
return function() {
clearTimeout(timer)
timer = setTimeout(() => {
let args = arguments
fun.apply(this, args)
}, 5000)
}
}
// 节流
let btn2 = throttle(use,2000)
function use() {
console.log("二技能已释放")
}
function throttle(fun,time) {
let t1 = 0
return function() {
let t2 = new Date()
if (t2 - t1 > time) {
fun.apply(this, arguments)
t1 = t2
}
}
}
</script>
语义化解释
LOL或者王者荣耀都玩过吧。
回城嘲讽这招用过吧?放技能都会吧?
1:那么我可以说,回城这个事件就是防抖。假设回城需要5秒,你不断回城嘲讽对面,即使你这个行为持续了10秒那么你也是无法回到泉水,倘若你在嘲讽3秒后就停止了嘲讽,那么从第3秒开始重新计算,5秒后你就能回到泉水。
防抖
就是在不断的操作中(输入、点击等)最终只执行一次的一种提高性能的方法。
2:那么放技能就是节流,假设二技能CD(冷却)是2秒,那么你点击了二技能,技能释放,在2秒内你无论点多少次技能按钮,也不会再次释放技能。也就是说6秒内你只能放3次技能,第4次技能得等6秒完全过完才能释放。
日常开发中我们滚动鼠标滚轮监听滚动条位置,防止按钮多次点击等就会用到。节流说白了就是在间隔一段时间触发只会执行一次
防抖的代码实现
1:首先我们模拟一个回城的按钮,并且给他绑定一个事件。最终效果我们想实现点击后模拟5秒后回城事件。
<button onclick="goHome()">回城(需要5秒)</button>
function goHome() {
console.log("成功回到泉水~~")
}
假设用打印出的内容模拟真实结果,那么此时明显不合理,因为代表我一点击就回到泉水。
2:很容易想到要用定时器来实现这个延时5秒回到泉水的操作。我们定义一个函数debounce,传入一个方法作为参数。当我们调用debounce(goHome)时,5秒后便可以打印出“成功回到泉水~~”。
<button onclick="btn()">回城(需要5秒)</button>
let btn = debounce(goHome)
function goHome() {
console.log("成功回到泉水~~")
}
function debounce(fun) {
return function() {
setTimeout(() => {
fun()
}, 5000)
}
}
现在延时的目的是达到了但是每次点击都会新增一个新的setTimeout
而且并不能达到我们多次点击只执行一次的效果。当我连续点击2次或多次以后,实际上触发了多个计时器,在一定时间过后,点了多少次就会有多少次"成功回到泉水~~"输出。
这显然不是我想要的(因为如果这样我岂不是不能回城嘲讽了)。
这时可以用clearTimeout
,我们希望在点击了按钮之后也就是debounce
执行时要先把之前的setTimeout
先清除再重新计时。
function debounce(fun) {
let timer = null
return function() {
clearTimeout(timer)
timer = setTimeout(() => {
fun()
}, 5000)
}
}
现在一个防抖功能就ok了,但是,如果我们在goHome()
打印this
会发现我们这样执行的this
是指向Window
的。使用apply
来改变this
指向,再一个需要考虑到执行函数的参数,因为不同的函数肯定会有不同的参数传入,对于参数我们可以使用arguments
处理。
function debounce(fun) {
let timer = null
return function() {
clearTimeout(timer)
timer = setTimeout(() => {
let args = arguments
fun.apply(this, args)
}, 5000)
}
}
节流的代码实现
1:同样的我们模拟一个技能释放按钮,同样的也绑定一个事件。最终效果我们想实现模拟2秒内只能释放一次技能事件。
<button onclick="btn2()">技能(2秒冷却)</button>
2:具体思维类似防抖,就不具体写
// 节流
let btn2 = throttle(use,2000)
function use() {
console.log("二技能已释放")
}
function throttle(fun,time) {
let t1 = 0
return function() {
let t2 = new Date()
if (t2 - t1 > time) {
fun.apply(this, arguments)
t1 = t2
}
}
}
这里我们记录了两个时间:t1表示
初始时间,t2表示
当前时间,如果当前时间距离上一个时间也就是初始时间大于所设置的2000
。
那我们就可以执行fun()
并且把初始时间变更为这一次执行的时间,这样每次我们执行过后t1
就变成了上一次执行的时间。这样一个节流功能就完成了。