手写代码代码系列之防抖与节流


2020-10-12 前端基础

前言

面试遇到手写题一脸懵逼的你也许一定想问:网上代码一堆,随便抄一下不香吗,为什么要手写?关于这个问题最直接的回答:为了区分厉害的和普通的。但坦白来讲,会白板实现关键功能的人,实现业务需求的效率一定更高。现在是一个内卷时代,我们要脱颖而出,只能参与进去,尽量跑快点。所以手写一定搞起来。 let's go

唠嗑

事件的触发权很多时候都属于用户,有些情况下会产生问题:

  • 向后台发送数据,用户频繁触发,对服务器造成压力
  • 一些浏览器事件:window.onresize、mousemove等,触发的频率非常高,会造成浏览器性能问题

如果你碰到这些问题,那就需要用到这些技术了。

我们先来解释一下**函数节流(Throttling)函数防抖(Debouncing)**的区别:

我们上班、生活每天都需要坐电梯,用这个比喻再恰当不过了:

函数防抖和我们平时坐电梯差不多,如果有人进电梯(用户触发事件),那将在10秒钟后出发(执行程序),这时如果又有人进电梯了(用户在10秒内再次触发事件),我们又得等10秒再出发(重新计时)。

函数节流就比较直观了,有人进电梯,就开始计时,每10秒运送一次,如果没有人,则待机。

这两种策略具体使用场景还得看你的实际需求了,但是,只要理解了这个思想,接下来的就好办了。

节流函数

节流函数是在一些高频的事件中,让这些事件在每隔单位时间n内只执行一次,达到优化目的; 根据这个,我们有两种实现方式;

  • 第一种是利用时间戳的方式来判断是否已到执行时间,记录上次执行的时间,然后每次触发执行回调,回调中判断当前的时间戳比上次执行时间戳大于约定的单位时间,如果是则更新执行事件,如此循环;
  • 第二种方法是使用定时器,比如当 scroll 事件刚触发时,打印一个 hello world,然后设置个 1000ms 的定时器,此后每次触发 scroll 事件触发回调,如果已经存在定时器,则回调不执行方法,直到定时器触发,handler 被清除,然后重新设置定时器。

第一种方式,时间差;

const throttle=function(fn,waitTime){
  let startTime=0;
  return function(...args){
    let endTime=+new Date();
    if(endTime-startTime>waitTime){
      startTime=endTime;
      fn.apply(this,args)
    }
  }
}

let aaa=throttle(()=>{
  console.log('执行拉')
},2000)

// setInterval(aaa,50)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

第二种方式,定时器;

const throttle=function(fn,waitTime){
  let time;
  return function(){
    if(!time){
      time=setTimeout(()=>{
        tiem=null;
        fn.apply(this,...args)
      },waitTime)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
Thomas: 11/20/2020, 4:35:13 PM