debounce & throttle

2 篇文章 0 订阅

debounce

原理

监听一个输入框,文字变化后触发change事件,如果直接用keyup事件,则会频繁触发change事件
防抖:用户输入结束或暂停的时候,才会触发change事件
应用场景: search框联想,注册的时候提示是否已注册等

<body>
  <div class="test">
    <input id='input1'>
  </div>
  <script>
    const input1 = document.getElementById('input1')
    // 糟糕的情况 每次输入文字都会输出值
    input1.addEventListener('keyup', function () {
      console.log(input1.value);
    })
  </script>

</body>

希望停半秒钟(自定义)发送一个请求,再输入也是停半秒钟的时候发送一个请求
这种机制称为防抖

在这里插入图片描述

<body>

  <div class="test">
    <input id='input1'>
  </div>
  <script>
    const input1 = document.getElementById('input1')
    // 糟糕的情况 每次输入文字都会输出值
    // input1.addEventListener('keyup', function () {
    //   console.log(input1.value);
    // })

    let timer = null
    input1.addEventListener('keyup', function () {
      // 如果有timer就清掉它
      timer&&clearTimeout(timer)
      timer = setTimeout(()=>{
        // 触发事件
        ajax()
        // 清空定时器
        timer=null
      },500)
    })

    function ajax() {
      console.log("ajax---",input1.value);
    }
  </script>

</body>

现在输入123(间隔小于0.5s) 来根据原理图看一下他的代码执行顺序
请添加图片描述

封装debounce函数

    const input1 = document.getElementById('input1')

    input1.addEventListener("keyup", debounce(function(){
      console.log(input1.value);
    },600))

    function debounce(fn, delay = 500) {
      // 注意timer是在闭包中的
      // 扩展  闭包一般在什么情况下用呢 ?  这个是作为函数作用域返回值
      // 外部不会轻易拿到 所以不会导致timer逻辑混乱
      let timer = null
      return function () {
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          fn()
          // fn函数在执行的时候,会把当前的this,arguments传进来
          // 返回的fn可能会有一些参数,还要把this传进来,如果用this的话那就不能
          // 用箭头函数了 只能用function形式了
          // fn.apply(this,arguments)
      
          timer = null
        }, delay)
      }
    }

总代码

 <!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <div class="test">
    <input id='input1'>
  </div>
  <script>
    const input1 = document.getElementById('input1')
    let a =123
    input1.addEventListener("keyup", debounce(ajax,600,a))
    function debounce(fn, delay = 500) {
      let timer = null
      return function () {
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          fn.apply(this,arguments)
          timer = null
        }, delay)
      }
    }
    function ajax(aa) {
      console.log("ajax---", input1.value);
    }
  </script>

</body>

</html>

throttle

原理

保持一个频率连续触发

使用场景,拖拽一个元素的时候,要随时拿到该元素被拖拽的位置,比如拖拽排序,需要随时判断位置是否到达了要拖拽到的位置
如果直接用drag事件,则会频繁触发,很容易导致卡顿
这时候需要节流,无论拖拽速度多快,都会每隔100ms触发一次 对计算机来说 这是一个比较宽裕的时间

没有经过节流的代码

<div class="div1" draggable="true">拖拽</div>
    const div1 = document.getElementsByClassName('div1')[0]
    console.log(div1);
    div1.addEventListener("drag",(e)=>{
      // console.log(e);
      console.log(e.offsetX+' '+e.offsetY);
    })

在这里插入图片描述
经过节流的代码

    const div1 = document.getElementsByClassName('div1')[0]
    // console.log(div1);
    let timer = null
    div1.addEventListener("drag",(e)=>{
      // console.log(e);
      if(timer){
        return 
      }
      timer = setTimeout(() => {
        console.log(e.offsetX+' '+e.offsetY);
        timer = null
      }, 500);
     
    })

在这里插入图片描述

这个代码应该好懂
拖拽事件不断被触发,只要timer有值就return 等到设定的时间到了,timer清空,这时候才可以重新计时

封装throttle函数

     // 节流封装函数
     function throttle(fn, delay = 500) {
      let timer = null
      return function () {
        if (timer) {
         return 
        }
        timer = setTimeout(() => {
          fn.apply(this,arguments)
          timer = null
        }, delay)
      }
    }
   div1.addEventListener("drag", throttle(function (e) {
      console.log(e.offsetX);
    }, 100));

apply

apply作用,第一个绑定this,第二个绑定参数
参数在什么地方有用呢
这里是没有问题的

    div1.addEventListener("drag",function(e) {
      console.log(e);
    });

但是在这里
在这里插入图片描述

e会传给谁?他会传给throttle返回的函数
在这里插入图片描述
这个函数接收e
他不会传给throttle包裹的函数
在这里插入图片描述
那如何让包裹的函数也有e呢
那就需要通过apply把arguments传进去
如果是settimeout里面运行fn的话
那么e会是undefined
在这里插入图片描述
一篇好文章
https://www.zhihu.com/people/peng-leonard/posts

遇到的问题

疑问 根本就不会进入到回调函数里面,因为他只是返回了函数,并没有执行
在这里插入图片描述
但是这样就可以
在这里插入图片描述
或者是这样
在这里插入图片描述

分析一下上面的问题

问一个好友要了一个防抖代码 ,但是他没有封装
在这里插入图片描述

我的理解
在这里插入图片描述
这两种方法有什么不同呢
$watch api 第二个参数的函数可以接收一个参数,输出出来是query的值,

这里调用了debounce,debounce返回的是这个函数
在这里插入图片描述
多次输入值的话 debounce函数不会再执行第二次 只会执行返回的函数
相当于第二个参数是这个匿名函数, timer通过闭包保存值

但是用在watch回调函数里面的话
在这里插入图片描述
相当于这里只是有了一个函数,但是并没有执行
如果执行呢 query每次变化的时候,都会重新调用debounce方法,都会重新返回一个函数,所以没有防抖的效果 而且他不能传入参数
那怎么解决呢

在这里插入图片描述
把debounce作为监听函数就可以了

但是就是想这样写怎么办呢

在这里插入图片描述
在这里插入图片描述
这样的话$watch 第二个参数就不能用debounce2了
这里为什么要命名timer2 呢 如果前面还有个节流之类的代码要用到timer呢,这样的话会冲突的,会很难管理 ,这就是为什么要用到闭包(timer不会被外部所影响)。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: debounce 和 throttle 是两种用于限制函数调用频率的技术。 debounce 函数会在一定时间内把多次函数调用合并成一次。例如,我们希望限制用户在输入框中输入的频率,以免服务器压力过大。我们可以使用 debounce 函数,设置一个延迟时间,在用户停止输入后一段时间内只执行一次回调函数。 throttle 函数会在一定时间内限制函数的调用次数。例如,我们希望限制用户滚动页面时图片懒加载的频率,以免影响性能。我们可以使用 throttle 函数,设置一个执行频率,在规定时间内只执行一次或几次回调函数。 ### 回答2: debounce函数和throttle函数都是用于处理频繁触发的事件,以减轻性能负担和提高用户体验的函数。 debounce函数会在规定的延迟时间内,只执行最后一次触发的事件。例如,在一个输入框中实时搜索关键字,如果在用户连续输入时立即处理搜索逻辑,可能会导致多次无意义的请求。使用debounce函数可以在用户输入完成后的一段时间内,再处理搜索逻辑,避免了频繁操作。 throttle函数会在规定的时间间隔内,按照规定的频率执行事件。例如,在滚动页面时,如果在每次滚动时都触发一次事件,可能会导致页面卡顿。使用throttle函数可以控制触发事件的频率,比如每隔200毫秒触发一次事件,以减轻页面负担。 举个例子来说明其用法: 假设有一个按钮需要防止多次点击: ```html <button id="btn">点击</button> ``` 使用debounce函数来防止多次点击: ```javascript function debounce(func, delay) { let timerId; return function (...args) { clearTimeout(timerId); timerId = setTimeout(() => { func.apply(this, args); }, delay); }; } function handleClick() { console.log("按钮被点击"); } const btn = document.getElementById("btn"); btn.addEventListener("click", debounce(handleClick, 200)); ``` 在这个例子中,通过使用debounce函数,当按钮被多次点击时,只有在最后一次点击后的200毫秒内才会触发handleClick函数,避免了多次点击产生多个事件的问题。 类似地,使用throttle函数可以控制按钮点击的频率,保证每隔一定时间间隔才能触发事件。 ### 回答3: debounce 函数和 throttle 函数是用来控制函数调用频率的工具函数。 debounce 函数的作用是延迟执行函数,当事件被触发后,函数不会立即被执行,而是延迟一段时间后执行。如果在延迟期间内又触发了相同的事件,那么之前的延迟会被取消,重新开始计时。这样可以避免在连续触发事件时频繁执行函数,提高性能。 举个例子,比如在网页输入框中实时搜索功能的实现。当用户输入时,我们希望能够在用户停止输入一段时间后才执行搜索操作,以避免频繁请求服务器。这时可以使用 debounce 函数来延时执行搜索函数,只有在用户停止输入一段时间后才真正执行搜索操作。 throttle 函数的作用是限制函数的执行频率,即无论触发多少次事件,函数都不会连续执行,而是固定时间间隔内执行一次。它可以用来控制一个函数在短时间内不能被频繁调用,以避免性能问题。 举个例子,比如在网页上绑定鼠标滚动事件时,如果没有对事件进行处理,每次鼠标滚动都会触发滚动事件,而滚动事件可能会执行一些复杂的操作,这样会导致性能问题。这时可以使用 throttle 函数来限制滚动事件的触发频率,比如每隔 100ms 执行一次滚动事件处理函数,这样可以降低函数的执行次数,提高性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值