美文网首页
防抖和节流

防抖和节流

作者: 风向应该可以决定发型吧 | 来源:发表于2020-11-18 01:14 被阅读0次

防抖和节流

防抖

在准备执行某项操作时,预设一个间隔时间,然后计时,达到预设的时间间隔之后才执行逻辑;
在没到达间隔时间这段时间内,如果有多次重复操作,那么后面的操作会顶替掉前面的计时任务,重新开始计时。

应用场景: 输入框输入内容过程中去服务器查询数据,不能每次input都去查询,所以只有当用户输入停顿一定时间间隔时,认为用户希望获得查询结果。

代码如下:

/**
 * 防抖: 重复操作重置定时器
 */
function debounce (callback, delay, immediate) {
  let timer, context, args, isExecuted;

  let run = () => {
    timer = setTimeout(() => {
      !isExecuted && callback.apply(context, args);
      clearTimeout(timer);
      timer = null;
    }, delay)
  }

  return function() {
    context = this;
    args = arguments;
    // 重复进入时,设置为false,用于 run内部进行判断
    // 若没有此标志位,run内只能用 immediate 来判断优化
    // 但问题是,如果使用immediate,那么定时器完成后始终不会执行callback
    isExecuted = false;

    // 定时器存在时,清空并重建
    // 没有必要释放timer,因为run方法会重新赋值
    if (timer) {
      clearTimeout(timer);
      run()
    } else {
      // timer不存在的两种情况
      // 1. 初始状态,还没有创建任何定时器
      // 2. 完成了一次执行,timer被释放
      // 所以当timer不存在时,需要创建;
      // timer存在时,说明还在进行计时,此时需要清除定时器并重新创建
      !!immediate && callback.apply(context, args);
      isExecuted = true; // 标记为已执行
      run();
    }
  }
}

测试代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>节流Throttle</title>
  <style>
    #container {
      width: 200px;
      height: 200px;
      text-align: center;
      line-height: 200px;
      background-color: gray;
      color: white;
    }
  </style>
</head>
<body>
  <input id="input" type="text">
  <span>input输入结果</span>
  <script>
    window.onload = () => {
      var inputEl = document.getElementById('input');

      inputEl.addEventListener('input', debounce(function(e) {
        this.nextElementSibling.textContent = this.value
      }, 1000, true));
    }

    /**
     * 防抖: 重复操作重置定时器
     */
    function debounce (callback, delay, immediate) {
      let timer, context, args, isExecuted;

      let run = () => {
        timer = setTimeout(() => {
          !isExecuted && callback.apply(context, args);
          clearTimeout(timer);
          timer = null;
        }, delay)
      }

      return function() {
        context = this;
        args = arguments;
        // 重复进入时,设置为false,用于 run内部进行判断
        // 若没有此标志位,run内只能用 immediate 来判断优化
        // 但问题是,如果使用immediate,那么定时器完成后始终不会执行callback
        isExecuted = false;

        // 定时器存在时,清空并重建
        // 没有必要释放timer,因为run方法会重新赋值
        if (timer) {
          clearTimeout(timer);
          run()
        } else {
          // timer不存在的两种情况
          // 1. 初始状态,还没有创建任何定时器
          // 2. 完成了一次执行,timer被释放
          // 所以当timer不存在时,需要创建;
          // timer存在时,说明还在进行计时,此时需要清除定时器并重新创建
          !!immediate && callback.apply(context, args);
          isExecuted = true; // 标记为已执行
          run();
        }
      }
    }

  </script>
</body>
</html>

节流

当短时间内重复执行某项操作时,予以忽略,只执行一次;知道执行完成之后才会重新添加执行能力。

实现原理: 维护一个定时器,每次执行操作是都判断定时器是否存在,如果定时器存在,直接return;
如果定时器不存在,则创建定时器,定时器到期后执行,并清除定时器和定时器标志

代码如下:

const throttle = (callback, delay, immediate) => {
  let timer, context, args;

  let run = () => {
    timer = setTimeout(() => {
      // 仅在不是立即模式时执行,防止二次执行
      // 当 immediate 为 true时, run方法的作用仅用于创建定时器,用于下次执行控制
      if (!immediate) callback.apply(context, args)

      clearTimeout(timer) // 清除定时器,
      timer = null // 回收timer,防止对后面的执行造成影响
    }, delay)
  }

  return function() {
    // 存储上下文和实参列表
    context = this;
    args = arguments;

    // 当前如果有定时器任务,则取消操作
    if (timer) return

    // 如果需要立即执行,则执行
    if (immediate) callback.apply(context, arguments)
    // 再次执行run方法创建定时器用于下次判断
    run()
  }
}

测试:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>节流Throttle</title>
  <style>
    #container {
      width: 200px;
      height: 200px;
      text-align: center;
      line-height: 200px;
      background-color: gray;
      color: white;
    }
  </style>
</head>
<body>
  <div id="container"></div>
  <script>
    window.onload = () => {
      var containerEl = document.getElementById('container');
      var i = 0;
      containerEl.addEventListener('mousemove', throttle((e) => {
        containerEl.textContent = i++
      }, 200, true));
    }

    /**
     * 节流
     */
    const throttle = (callback, delay, immediate) => {
      let timer, context, args;

      let run = () => {
        timer = setTimeout(() => {
          // 仅在不是立即模式时执行,防止二次执行
          // 当 immediate 为 true时, run方法的作用仅用于创建定时器,用于下次执行控制
          !immediate && callback.apply(context, args);
          clearTimeout(timer) // 清除定时器,
          timer = null // 回收timer,防止对后面的执行造成影响
        }, delay)
      }

      return function() {
        // 存储上下文和实参列表
        context = this;
        args = arguments;
        
        if (timer) return; // 当前如果有定时器任务,则取消操作

        !!immediate && callback.apply(context, args); // 如果需要立即执行,则执行
        run() // 再次执行run方法创建定时器用于下次判断
      }
    }
  </script>
</body>
</html>

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>节流Throttle</title>
  <style>
    #container {
      width: 200px;
      height: 200px;
      text-align: center;
      line-height: 200px;
      background-color: gray;
      color: white;
      margin-top: 20px;
    }
  </style>
</head>
<body>
  <input id="input" type="text">
  <span>input输入结果</span>
  <div id="container"></div>
  <script>
    window.onload = () => {
      var inputEl = document.getElementById('input');
      var containerEl = document.getElementById('container');
      var i = 0;

      inputEl.addEventListener('input', debounce(function(e) {
        this.nextElementSibling.textContent = this.value
      }, 1000, true));

      containerEl.addEventListener('mousemove', throttle((e) => {
        containerEl.textContent = i++
      }, 200, true));
    }

    /**
     * 防抖: 重复操作重置定时器
     */
    function debounce (callback, delay, immediate) {
      let timer, context, args, isExecuted;

      let run = () => {
        timer = setTimeout(() => {
          !isExecuted && callback.apply(context, args);
          clearTimeout(timer);
          timer = null;
        }, delay)
      }

      return function() {
        context = this;
        args = arguments;
        // 重复进入时,设置为false,用于 run内部进行判断
        // 若没有此标志位,run内只能用 immediate 来判断优化
        // 但问题是,如果使用immediate,那么定时器完成后始终不会执行callback
        isExecuted = false;

        // 定时器存在时,清空并重建
        // 没有必要释放timer,因为run方法会重新赋值
        if (timer) {
          clearTimeout(timer);
          run()
        } else {
          // timer不存在的两种情况
          // 1. 初始状态,还没有创建任何定时器
          // 2. 完成了一次执行,timer被释放
          // 所以当timer不存在时,需要创建;
          // timer存在时,说明还在进行计时,此时需要清除定时器并重新创建
          !!immediate && callback.apply(context, args);
          isExecuted = true; // 标记为已执行
          run();
        }
      }
    }

    /**
     * 节流
     */
    const throttle = (callback, delay, immediate) => {
      let timer, context, args;

      let run = () => {
        timer = setTimeout(() => {
          // 仅在不是立即模式时执行,防止二次执行
          // 当 immediate 为 true时, run方法的作用仅用于创建定时器,用于下次执行控制
          !immediate && callback.apply(context, args);
          clearTimeout(timer) // 清除定时器,
          timer = null // 回收timer,防止对后面的执行造成影响
        }, delay)
      }

      return function() {
        // 存储上下文和实参列表
        context = this;
        args = arguments;
        
        if (timer) return; // 当前如果有定时器任务,则取消操作

        !!immediate && callback.apply(context, args); // 如果需要立即执行,则执行
        run() // 再次执行run方法创建定时器用于下次判断
      }
    }
  </script>
</body>
</html>

相关文章

  • 谈谈js中的节流和防抖函数

    关于节流和防抖,这篇文章说的很好了,深入lodash源码分析防抖和节流深入篇 | Lodash 防抖和节流是怎么实...

  • JavaScript防抖和节流

    1. 认识防抖和节流 1.1. 对防抖和节流的认识 防抖和节流的概念其实最早并不是出现在软件工程中,防抖是出现在电...

  • 前端性能优化-浅谈js防抖和节流

    浅谈js防抖和节流

  • Javascript 基础

    1、函数防抖和函数节流 【《javascript高级程序设计》里,函数节流是这里讲的函数防抖。】函数防抖: 在事件...

  • js 防抖 节流

    节流 防抖1 防抖2

  • 2019-03-27

    js的防抖和节流 据我所知防抖和节流都是为了优化作用,减轻浏览器和服务端的负担,防抖和节流俩个的英文要记住: de...

  • js的防抖和节流

    js的 防抖(debounce)和 节流(throttle ) 防抖和节流一般用于高频触发事件,属于浏览器性能优化...

  • 手写防抖和节流函数实现

    1. 认识防抖和节流函数 防抖和节流的概念其实最早并不是出现在软件工程中,防抖是出现在电子元件中,节流出现在流体流...

  • 实现防抖和节流

    一、认识防抖和节流函数 防抖和节流的概念其实最早并不是出现在软件工程中,防抖是出现在电子元件中,节流出现在流体流动...

  • 2019-04-24关于节流和防抖

    节流: 应用场景: 防抖: 应用场景: 1.节流 2.防抖

网友评论

      本文标题:防抖和节流

      本文链接:https://www.haomeiwen.com/subject/jukqiktx.html