震惊!拉动一下控制台大小,后台请求数量爆炸,竟是没做好防抖与节流!!

8,265 阅读4分钟

前言

最近有个朋友在面试过程中遇到一个问题:什么是防抖节流?糟了,这可触碰到我的知识盲区了,好像听也没听过这2个东西,痛定思痛,赶紧学习学习。


防抖(debounce)

在事件被触发n秒之后执行,如果在此期间再次触发事件,则重新开始计时。

乍一看,这不是闲的蛋疼吗?为啥要等n秒之后再执行呢?

本着存在即合理的原则,咱看不懂但咱得去学啊!经过十秒钟的思考,突然想起来之前做过的公司的一个小程序,使用的mpvue+vant-weappvan-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震惊部了

公司的大数据组件目前是只要页面大小发生变化就会重新加载,这就导致了有时候拉一下控制台会发生很多次请求,这个时候就可以用防抖来解决一下了~