点击上方?Java编程技术乐园,轻松关注!及时获取有趣有料的技术文章
文章很好,耐心阅读,记得点赞和关注哦~
前言
最近有个朋友在面试过程中遇到一个问题:什么是防抖和节流?糟了,这可触碰到我的知识盲区了,好像听也没听过这 2 个东西,痛定思痛,赶紧学习学习。
防抖(debounce)
在事件被触发 n 秒之后执行,如果在此期间再次触发事件,则重新开始计时。
乍一看,这不是闲的蛋疼吗?为啥要等 n 秒之后再执行呢?
本着存在即合理的原则,咱看不懂但咱得去学啊!经过十秒钟的思考,突然想起来之前做过的公司的一个小程序,使用的 mpvue+vant-weapp,van-field 标签并没有和数据进行双向绑定,而是每次都要触发 @input 事件,从而完成数据绑定:
这就导致了一个问题:
输一个手机号要触发 11 次事件!!如果是联想搜索的话。。。那画面太美!
我们先自己想一下办法来解决这个问题。
- 首先我们需要在手机号输入完成之后将数据绑定到 phoneNumber 上然后进行联想搜索,怎么算输入完成呢,输入一个数字到找到下一个数字输入大概需要 1 不到秒,只要用户一秒内没有再次输入,则将输入框内容与 phoneNumber 绑定并进行联想搜索(什么?你说你输入五个字符就停下?不怕后台砍死你)。
- 准备工具:一个需要触发的函数 debounce、一个定时器、一个输入框、一个判断是否输入完成的函数 getPhone。
- 基本思路:输入绑定事件 getPhone,输入之后开启1秒定时器,如果在 1 秒内再次进行了输入,则清除之前的定时器,并且重新设置定时器;如果 1 秒内没有输入,则输入结束触发事件 a,进行联想搜索。
<input?id="phone"?type="text"/>
//?需要触发的函数
function?debounce(d){
????console.log("联想搜索phoneNumber:"?+?d)
}
let?inp?=?document.querySelector("#phone");
//?输入触发的事件
function?getPhone(fn,delay){
????let?timer;
????//?使用闭包,保证每次使用的定时器是同一个
????return?(d)=>{
????????clearTimeout(timer);
????????timer?=?setTimeout(()=>{
????????????fn(d);
????????????//?结束之后清除定时器
????????????clearTimeout(timer);
????????},delay)
????}
}
let?getPhoneDebounce?=?getPhone(debounce,1000);
inp.addEventListener('keyup',(e)=>{
????getPhoneDebounce(e.target.value);
})
这时候看输出:
是的只输出了一次号码,也就是说不用每次输入都进行一次搜索了。
节流(throttle)
如果持续触发一个事件,则在一定的时间内只执行一次事件。
那么问题来了,既然是持续触发了,那为啥还要设定一定时间内只执行一次呢?废话,你吃鸡为啥不用 AKM 非要去追梦抢狗杂呢?还不是因为 AKM 射速慢(狗杂真香)!
我们来试着做一个 AKM 的设计模拟:
- 首先第一次点击射击的时候,打出一发子弹,当以极短的时间再次点击射击的时候,由于需要‘冷却’——也就是节流,再次点击无效,当冷却时间过了之后,再次点击射击,则继续下一次射击。
- 准备工具:一个射击的函数 shot,一个判断射击间隔是否结束的函数 nextShot,一个触发射击的按钮,判断射击是否结束的定时器 timer。
- 基本思路:第一次点击按钮的时候,触发 shot,当继续点击的时候,射击无效,只有过了定时器设置的时间才可以继续射击。
<button?id="shot">射击</button>
function?shot(){
????console.log('射击')
}
let?btn?=?document.querySelector('#shot');
function?nextShot(fn,delay){
????let?timer;
????//?闭包原理同上
????return?()=>{
????????//?定时器存在,无法射击
????????if(timer){
????????????console.log('禁止射击');
????????}else{??//?定时器不存在,射击,并设置定时器
????????????fn();
????????????timer?=?setTimeout(()=>{
????????????????//?定时器结束,可以射击
????????????????clearTimeout(timer);
????????????????timer?=?null;
????????????},delay)
????????}
????}
}
let?start?=?nextShot(shot,20);
btn.addEventListener('click',()=>{
????start();
})
当我们疯狂点击按钮的时候:
可能这个例子不是很突出,我再说个类似的,英雄联盟和DNF的技能冷却应该更适合~
是时候回归一下标题了,免得有人说我可以去 UC 震惊部了!公司的大数据组件目前是只要页面大小发生变化就会重新加载,这就导致了有时候拉一下控制台会发生很多次请求,这个时候就可以用防抖来解决一下了~
作者:.Ping
链接:https://juejin.im/post/5e0d7ab9f265da5d691035b5
来源:掘金