zoukankan      html  css  js  c++  java
  • 一文读懂函数的防抖和节流

    什么是防抖和节流?

    「 防抖 」

    场景:输入名称的同时去服务器校验名称是否重复,如果代码没做限制,输一次发一次请求;多次点击触发事件

    在事件被触发n秒后在执行回调函数,如果在n秒内又触发,则重新计时

     假设一个场景:鼠标划过一个div,触发onmousemove事件,它内部的文字会显示当前鼠标的坐标。

    防抖:函数防抖,这里的抖动就是执行的意思,而一般的抖动都是持续的,多次的。假设函数持续多次执行,我们希望它冷静下来再执行。也就是当持续触发事件的时候,函数是完全不执行的,等最后一次触发结束的一段时间之后,再去执行。

    分解一下需求:

    • 持续触发不执行
    • 不触发的一段时间之后在执行

     那么怎么实现上述的目标呢?

    •  在不触发的时间内在执行,那就需要一个定时器,
    •  定时器里面调用我们要执行的函数,将arguments传入,封装一个函数,让持续触发的事件监听我们封装的这个函数,将目标函数作为回调传进去,第二点就实现了
    •  再看第一点:持续触发不执行。我们先思考一下,是什么让我们的函数执行了呢?是上边的setTimeout。
    •  OK,那么现在的问题就变成了持续触发,不能有 setTimeout,这样直接在持续触发的时候,清掉计时器就好了。

    「 节流  」

    节流的会用在input,keyup更频繁触发事件中如resize、touchmove。「节流」会强制函数以固定的速率执行。节流的概念可以想象一下水坝,你建了水坝在河道中,不能让水流动不了,你只能让水流的慢一些。换言之,你不能让用户的方法都不执行,如果这样干,就是「防抖」了。

     节流的意思是让函数有节制的执行,而不是毫无节制的触发一次就执行一次。什么叫有节制呢?就是在一段时间内触发一次。

     分解一下需求:

    •  持续触发并不会执行多次
    •  到一定时间再去执行

     那么怎么实现上述的目标呢?

    •  持续触发,并不会执行,但是时间到了就会执行。抓取一个关键的点执行的时机」。
    •  要做到控制执行的时机,我们可以通过一个开关,与定时器setTimeout结合完成。
    •  函数执行的前提条件是开关打开,持续触发时,持续关闭开关。
    •  等到setTimeout到时间了再把开关打开,函数就会执行了。

     注:这里的throttle函数执行的结果是其内部return的function的调用,也就是说鼠标经过的事件监听实际上是这个被return的function,不断持续触发的是它。

           而 throttle函数只是提供了一个作用域,内部闭包声明一个run的开关变 量。

           由于闭包存在run这个变量会一直存在不被销毁,而let run = true只在这个闭包(局部作用域)内只声明了一次,但它不会被持续执行,所以return的函数内部的判断不会被它覆盖掉。

     总结:

     防抖和节流巧妙地用了setTimeout,来控制函数执行的时机,优点很明显,可以节约性能,不至于多次触发复杂的业务逻辑而造成页面卡顿。

     附上完整代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <style>
      #container {
        width: 500px;
        height: 200px;
        background: #ccc;
        font-size: 20px;
        text-align: center;
        line-height: 200px;
      }
    </style>
    <body>
      <div id="container"></div>
    </body>
    <script>
    // 防抖
    function debounce(func, delay){
      let timeout;
      return function() {
        clearTimeout(timeout)
        timeout = setTimeout(()=>{
          func.apply(this, arguments)
        },delay)
      }
    }
    const container = document.querySelector('div');
    // 调用方法
    container.onmousemove = debounce(function(e){
      container.innerHTML = `clientX = ${e.clientX},clientY ${e.clientY}`
    },1000);
    
    // 节流
    function throttle (func, delay  ) {
      let run = true;
      console.log ('触发的时候', run);
      return function ( ) {
        console.log ('return的函数内容', run); 
        if(!run) {
          return false // 如果关闭了开关,就不执行下面的代码
        }
        console.log ('判断开关关闭与否之后的', run);
        run = false; // 持续触发的话, run一直是false,就会停在上边的判断那里
        console.log ('开关关闭后', run);
        setTimeout(() => {
          func.apply(this, arguments);
          run = true;
          console.log ('开关打开后', run);
        }, delay)
      }
    }
    const container = document.querySelector('div');
    // 调用方法
    container.onmousemove = throttle(function(e){
      container.innerHTML = `clientX = ${e.clientX},clientY ${e.clientY}`
    },1000);
    </script>
    </html>

    在 PDFlux 中打开
    无数据
  • 相关阅读:
    我学的是设计模式的视频教程——辛格尔顿,生成器VS工厂方法
    android在广播接收器BroadcastReceiver里面再进行发送广播,造成当前广播接收器不断循环执行问题
    Android 出现警告Exported service does not require permission
    Android中如何像 360 一样优雅的杀死后台服务而不启动
    Android下写一个永远不会被KILL掉的进程/服务
    android 程序防止被360或者系统给kill掉
    android如何让service不被杀死
    如何让自己的Android程序永不被系统kill
    TextView的一些高级应用(自定义字体、显示多种颜色、添加阴影)
    Android ListView的背景和黑色边缘化的问题
  • 原文地址:https://www.cnblogs.com/cuixiaohua/p/12709663.html
Copyright © 2011-2022 走看看