“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
前言
防抖(debounce)和节流(throttle), 一直以来都是面试中的高频考点. 它们并不难, 可在你毫无准备的时候, 面试官要求手写一个防抖或节流, 许多面试者就会有些措手不及了, 笔者也是其中之一.
在经历痛苦面具后, 痛定思痛, 赶紧去学习了一下他们的手写, 在这里分享给大家. 干货满满, 建议收藏.🤗
概念
防抖和节流的概念想必大家都很清楚, 这里我就简单概述一下
防抖: 规定n 秒后执行回调, 在n 秒内触发则重新计时.
节流: 不管触发多少次, n 秒后只执行一次回调
有一个很好的例子
假设有一个电梯, 每次有人进来就等待15秒再关门, 每次有人进来就重新计时五秒,这就是防抖.
如果它每隔15秒就关门, 期间不管进来多少人,都保持这个时间间隔不变, 这就是节流.
开始手写debounce !
废话不多说, 直接先来个防抖的手写
debounce 接收两个参数, 一个回调函数和一个时间, 并返回一个函数
function debounce(func, time) {
// 在闭包空间中, 声明一个timer 作定时器,
// 它永久存在, 以便每次触发回调都可以操作到同一个timer
let timer
return function() {
// 接收外界传来的参数列表
let args = arguments
// 每次触发把之前的定时清除, 并设置新的计时, 重新计时
clearTimeout(timer)
timer = setTimeout(() => {
// 使用apply 改变func 函数this 指向
// 否则当函数运行的时候, this 会指向全局
func.apply(this, args)
}, time)
}
}
这里注意: 一定要改变this 指向, 否则setTimeout 在执行的之后, this 指向全局, setTimeout 中的函数也指向全局
debounce 场景应用
先来一个简单的输入框, 输入数据到页面
<input type="text" id="input" />
<div id="text"></div>
<script>
let text = document.getElementById('text')
let input = document.getElementById('input')
const inputText =(e) => {
text.innerHTML = e.target.value
}
input.addEventListener('keyup', inputText)
</script>
我们来看看效果
可以看到, 每次输入一个字母就推送一个字母到页面上
这个时候, 我们要需要用debounce 来做下优化
<input type="text" id="input" />
<div id="text"></div>
<script>
let text = document.getElementById('text')
let input = document.getElementById('input')
const inputText =(e) => {
text.innerHTML = e.target.value
}
let debounceInput = debounce(inputText, 500)
input.addEventListener('keyup', debounceInput)
</script>
我们再来看看防抖之后的效果
这样我们就得到了一个实现了防抖效果的函数, 是不是很简单, 接下来我们来看看节流函数
手写throttle !
废话不多少, 先把它写了再解释
function throttle(func, time) {
// 时间戳结合定时器
// 单纯时间戳最后一次不会触发回调
// 所以需要一个定时器, 给最后一次定时
let t1, deferTimer
return function() {
let args = arguments
let that = this
let t2 = +new Date()
// 每次触发将之前的定时清除
clearTimeout(deferTimer)
// t1 不为undefined 是其中一个条件
// 只有当节流触发过之后 t1 = t2 , 这时t1 才有值
if(t1 && t2 - t1 < time) {
deferTimer = setTimeout(() => {
func.apply(that, args)
t1 = t2
}, (time - (t2 - t1)))
// 间隔时间超过time 的时候执行回调
}else {
func.apply(that, args)
t1 = t2
}
}
到这里, 一个节流函数就写好了, 接下来我们看看它的使用场景
<style>
div {
width: 300px;
height: 300px;
background-color: pink;
font-size: 30px;
color: white;
text-align: center;
line-height: 300px;
}
<style/>
<div id="text">0</div>
<script>
let text = document.getElementById('text')
let count = 0
const moveText = () => {
text.innerHTML = count++
}
let throttleInput = throttle(moveText, 2000)
text.addEventListener('mousemove', throttleInput)
<script/>
让我们来看看效果吧
可以看到,当我们一直一定鼠标的时候,它会在两秒的间隔后加1
值得一提的是,当我们停下鼠标,这时经过定时器数字来到了6。
我们继续停止鼠标不动,等时间超过两秒,再次移动鼠标,神奇的事情发生了! 它立即跳动变成了数字7
这究竟是怎么回事呢,我们一起来分析分析
首先,当来到数字6时,定时器触发,t1 = t2 被执行, 当等待时间超过2秒时, 我们移动鼠标, 获取到新的t2 ,这时的t2 - t1 > 2000 ,所以else 中的语句被立即执行,即回调函数立即执行。
总结
用简单一点的话来说: 防抖是控制次数, 节流是控制频率。
写在最后
看到这里的小伙伴,如果这篇文章有帮助到你,请给我一个大大的赞👍~ 😊
文章中有不足的地方,也可以在评论中指出,感谢~🤗🤗🤗