31、防抖和节流

防抖:

  • 事件被触发n秒后执行回调,如果在这n秒内又被触发,则重新计时
  • 动作被延迟执行。事件被触发后,n秒后执行动作。
  • 比如 要搜索某个字符串,基于性能考虑,肯定不能用户每输入一个字符就发送一次搜索请求。此时可以使用js防抖,在用户停止输入的一段时间后(如10ms),我们才发一次请求

节流:

  • 规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
  • 动作被定期执行。固定时间内,只执行一次动作,若有新事件触发,不执行
  • 比如 用户输入过程中,每过10ms就查询一次相关字符串

防抖和节流的区别:

  • 同样是2s的等待周期,防抖是只要触发间隔在2s以内,它就重新计时
  • 节流是,2s给予一次执行时间函数机会,还能设置第一次和最后一次的操作是否执行。

防抖和节流策略的选择:

  • 如果事件触发是高频但是有停顿时,可以选择防抖
  • 在事件连续不断高频触发时,只能选择节流,因为防抖可能会导致动作只被执行一次,界面出现跳跃。

1、防抖

1.1 未使用防抖的情况

1)输入框的keyup事件为例。可以看到,每秒都会执行多次console事件。

    解决:可以使用js防抖,在用户停止输入的一段时间后(如500ms)触发判断

1.2 使用防抖后

可以看到,如果用户不断输入,则不会触发console事件,这是由于在规定的 500ms 时间间隔内重新触发了keyup事件,定时器重新开始计时。当用户在500ms的间隔内没有进行输入,则会触发事件。适用于实时判断用户输入的内容(如邮箱、电话)是否符合格式要求等场景。

1.3 防抖的实现

思想:每次触发事件时都取消之前的延时调用方法。

当用户触发点击事件 delay ms后,我们才发请求。所以我们每次都使用一个定时器来保存用户的操作,然后每次在延迟时间内触发点击事件时,都把上一次的定时器清除掉即可,这样就保证了延迟delay ms 后,只发一次请求。

//1. 实现防抖函数。触发事件 delay ms 后,再执行动作fn
function debounce(fn,delay){
  let timeout = null; //1) 存放定时器返回值,便于清除定时器
  return function(){
    clearTimeout(timeout); // 2) 每次触发事件时,把前一个事件的定时器清除掉
    timeout = setTimeout(() => {
      fn.apply(this, arguments); // 3) delay ms后执行动作fn。this指向触发该事件的div
    },delay) 
  }
}

// 定义动作
function sayHi(){
  console.log("防抖成功");
} 
// 触发box的点击事件.(为box添加点击事件,点击时执行debounce返回的函数)
let box = document.getElementById('box');
box.addEventListener('click', debounce(sayHi, 500));
<div id="box" style="height: 100px; width: 100px; background: cadetblue;"></div>

点击完一次,500ms后打印“防抖成功”。 

多次点击时,以最后一次点击结束开始计时,500ms后打印“防抖成功”。 ​​​​​​​​​​​​​​

2、节流

2.1 节流的使用场景

下面情况需要使用节流去解决:

1)window的 resize 和 scroll 事件

 如:滚动到页面底部加载更多,稍微滚动一下就会触发n多次scroll事件,如果每次触发scroll事件的时候都去判断一次是否已经滚动到了页面底部,无疑会造成资源的浪费。此时若使用js节流每隔一定的时间(如500ms)进行一次判断间隔期间只能有一次触发判断,既节省了资源,也不会影响用户体验。

2)鼠标不断点击触发,mousedown(单位时间内只触发一次)

如:点击提交按钮提交表单信息,不小心连续点了多次,就提交了多次。

解决:使用js节流定期执行,固定周期内,只提交一次。

2.2 节流的实现

高频事件触发,但在n秒内只会执行一次,所以节流会减少函数的执行频率

思路:每次触发事件时都判断当前是否有等待执行的延时函数
 

//1. 实现节流函数。每delay ms 执行一次动作fn
function throttle(fn, delay){
   var runFlag = false; //1) 判断当前是否有等待执行的延时函数。false: 没有等待执行的函数
   return function(){
     if(runFlag) { //2) 之前有等待执行的函数。由于delay内,只执行一次,故直接返回。
       return false;
     };
     runFlag = true; //3) 当前的函数等待执行  
     setTimeout(() => {
      fn.apply(this, arguments); //4) 过了delay后,执行动作fn。this指向被点击的div
      runFlag = false; //5) 当前函数执行完。没有等待执行的函数
     }, delay)
   }
}

// 定义动作
function sayHi(){
  console.log("节流成功");
} 
// 触发box的点击事件.(为box添加点击事件,点击时执行throttle返回的函数)
let box = document.getElementById('box');
box.addEventListener('click', throttle(sayHi, 1000));

在delay周期内,不管点击多少次,只有第一次点击时触发的动作才会在delay时间后执行

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值