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