修身养性,知行合一

  • 首页
  • 爱码
    • 系统
    • 数据库
    • JavaScript
    • CSharp
    • Python
  • 生活
    • 文化
    • 美食
  • 杂谈
  • 关于
修身养性,知行合一
码字,杂谈
  1. 首页
  2. 爱码
  3. 前端
  4. JavaScript
  5. 正文

手动实现JS节流

2020年6月24日 2231点热度 0人点赞 0条评论

什么是节流

在函数调用过程中,避免过于频繁的调用,而是间隔某一时间后调用一次的方法,叫做节流。

节流做什么

节流可以有效避免短时间内大量调用某一方法或数据,保证页面的稳定性和数据的准确性。

一个小的例子

使用 underscore 的节流功能来测试一下效果。

中文网址

在页面中直接导入 cdn 即可。

https://cdn.bootcss.com/underscore.js/1.9.1/underscore.js

未节流时的样子

将下面内容粘贴到一个 HTML 的 body 标签中。

<div
  id="container"
  style="width:100%;height:200px;line-height:200px;text-align:center;color:#fff;background-color:#444;font-size:30px;"
></div>
<script>
  let count = 0;
  let container = document.querySelector("#container");

  // 此处为高频调用函数
  function doSomething() {
    container.innerHTML = count++;
  }

  container.onmousemove = doSomething;
</script>

这段代码会生成一个灰色框,只要鼠标在其内部移动,就会调用 doSomething 函数,导致数字不断增长。

使用节流

同样地,将下面内容粘贴到一个新的 HTML 的 body 标签中。

<div
  id="container"
  style="width:100%;height:200px;line-height:200px;text-align:center;color:#fff;background-color:#444;font-size:30px;"
></div>
<script src="https://cdn.bootcss.com/underscore.js/1.9.1/underscore.js"></script>
<script>
  let count = 0;
  let container = document.querySelector("#container");

  // 此处为高频调用函数
  function doSomething() {
    container.innerHTML = count++;
  }

  container.onmousemove = _.throttle(doSomething, 300);
</script>

这里导入了 underscore 库,这个库会导出一个 _ 的对象,它包含一个 throttle 方法,该方法的作用就是节流。第一个参数是函数原型,第二个参数是响应时间,这里我们设置 300ms 后响应。

另外还可以设置是否第一次首先执行和最后一次是否执行,传入: {leading: false} 或 {trailing: false} 。当然,你也可以同时传入,但是需要注意,如果同时传入 false 的话,会出现 bug,该 bug 会导致下次启动时不响应 {leading: false} ,而是会立即执行第一次,这一点需要注意。

这次运行后,可以发现当鼠标移动时,不再一味地增加,而是每隔一段时间后(300ms)才会响应一次。

手动实现节流函数

利用时间戳方式

这样的方式会触发第一次,而不会触发最后一次。

function throttle(func, wait) {
  let context, args;
  let old = 0;
  return function () {
    context = this;
    args = arguments;
    let now = Date.now();

    if (now - old > wait) {
      // 立即执行
      func.apply(context, args);
      old = now;
    }
  };
}

利用定时器方式

这样的方式会触发最后一次,而不会触发第一次。

function throttle(func, wait) {
  let context, args, timeout;

  return function () {
    context = this;
    args = arguments;

    // 设置一个定时器,只有为空时才会触发,每次执行后都会重新设定一个定时器。
    if (!timeout) {
      timeout = setTimeout(() => {
        timeout = null;
        func.apply(context, args);
      }, wait);
    }
  };
}

合并为最终的完整本版

利用上面的两种实现方式,可以得到一个比较完整的版本。

function throttle(func, wait, options) {
  let context, args, timeout, result;
  let previous = 0;

  if (!options) options = {};

  let later = function () {
    // 这里控制再次出发时,第一次是否执行,当为双false时,也是这里会出现的问题。
    previous = options.leading === false ? 0 : Date.now();
    timeout = null;
    result = func.apply(context, args);
    if (!timeout) context = args = null;
  };

  var throttled = function () {
    context = this;
    args = arguments;

    let now = Date.now();

    // 第一次不执行,调整previous的值即可。
    if (!previous && options.leading === false) previous = now;

    if (now - previous > wait) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      // 立即执行
      previous = now;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    } else if (!timeout && options.trailing !== false) {
      // 设置一个定时器,只有为空时才会触发,每次执行后都会重新设定一个定时器。
      timeout = setTimeout(later, wait);
    }

    return result;
  };

  throttled.cancel = function() {
      clearTimeout(timeout);
      timeout = null;
      timeout = context = args = null;
  }

  return throttled;
}
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: JavaScript
最后更新:2020年6月24日

jeremyjone

这个人很懒,什么都没留下

打赏 点赞
< 上一篇
下一篇 >

文章评论

取消回复

文章目录
  • 什么是节流
  • 节流做什么
  • 一个小的例子
    • 未节流时的样子
    • 使用节流
  • 手动实现节流函数
    • 利用时间戳方式
    • 利用定时器方式
    • 合并为最终的完整本版
最新 热点 随机
最新 热点 随机
关于 *.vue 文件中使用 TypeScript 声明类型报错的解决方案 element table 加载时宽度闪烁问题 windows 无法登录便签、OneNote等应用 vue2 中 vuex 对 ts 的支持 封装一个极简的右键菜单 vue2 使用 @vue/composition-api 的一些问题
浅谈 IEnumerable 与 IQueryable 的区别 .NET Core将Json字符串反序列化为对象 使用 windows 命令启动某个程序 .NET Core 的 URL 中文路径编码问题 推荐一波起始页吧 @typescript-eslint/no-unused-vars 警告问题

(っ•̀ω•́)っ✎⁾⁾ 开心每一天

COPYRIGHT © 2021 jeremyjone.com. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

京ICP备19012859号-1

京公网安备 11010802028585号