0%

防抖节流

是什么

本质上是优化高频率执行代码的一种手段

如:浏览器的 resizescrollkeypressmousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能

为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用throttle(节流)和debounce(防抖)的方式来减少调用频率

定义

  • 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
  • 防抖: n 秒后再执行该事件,若在 n 秒内被重复触发,则重新计时

节流:

用时间戳实现:

1
2
3
4
5
6
7
8
9
10
11
12

function throttled(fn,delay=500){
let oldTime=new Date.now();
return function(...args){
let context=this;
let newTime=new Date.now();
if(newTime-oldTime>=delay){
fn.apply(context,args);
oldTime=new Date.now();
}
}
}

用定时器实现

1
2
3
4
5
6
7
8
9
10
11
12
function throttled(fn,delay=500){
let timer=null;
return function(..args){
let context=this;
if(!timer){//n秒内只运行一次,若在n秒内重复触发,只有一次生效
timer=setTimeout(()=>{
fn.apply(context,args);
timer=null;
},delay)
}
}
}

防抖:

1
2
3
4
5
6
7
8
9
10
function debounce(fn,delay=500){
let timer;
return function(...args){
let context=this;
clearTimeout(timer);
timer=setTimeout(()=>{
fn.apply(context,args);//n秒内只能触发一次,若在n秒内重复触发,都会被清除,重新计时
},delay)
}
}

立即执行的防抖函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function debounce(fn,delay=500,immediate){
let timer;
return function(...args){
let context=this;
if(timer)clearTimeout(timer);
if(immediate){
immediate=!immediate;
fn.apply(context,args);
}else{

timer=setTimeout(()=>{
fn.apply(context,args);
},delay)
}
}
}

区别

相同点:

  • 都可以通过使用 setTimeout 实现
  • 目的都是,降低回调执行频率。节省计算资源

不同点:

  • 函数防抖,在一段连续操作结束后,处理回调,利用clearTimeout setTimeout实现。函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能
  • 函数防抖关注一定时间连续触发的事件,因为会清除定时器,只在最后执行一次,而函数节流一段时间内只执行一次,不会清除定时器,因此会在隔一段时间执行一次。

例如,都设置时间频率为500ms,在2秒时间内,频繁触发函数,节流,每隔 500ms 就执行一次。防抖,则不管调动多少次方法,在2s后,只会执行一次

应用场景

防抖在连续的事件,只需触发一次回调的场景有:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

节流在间隔一段时间执行一次回调的场景有:

  • 滚动加载,加载更多或滚到底部监听
  • 搜索框,搜索联想功能