前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >带你“深入”节流

带你“深入”节流

作者头像
ClyingDeng
发布2023-03-04 17:55:11
6790
发布2023-03-04 17:55:11
举报
文章被收录于专栏:今天你敲代码了吗

说白话:

节流就像我们喝水上厕所一样... Emm咱们还是换个例子吧。。。

比如说吃饭。吃饭说明规定,五个小时吃一次。吃了一次饭,小狗蹦蹦哒哒地玩了五个小时。五个小时一到, 小狗再回来吃饭。依次类推,每五小时回来吃一次饭。

说人话:

定义:如果持续触发事件,单位时间内执行一次函数。

节流模样:

代码语言:javascript
复制
<!-- <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script>
<div class="box"></div>
<script>
let obox = document.querySelector('.box')
function todo(e) {
  console.log(this, e);
}
let throttleFn = _.throttle(todo, 1000)
obox.onmousemove = throttleFn
</script>

1.gif

我们可以直接使用lodash.js或者underscore.js中的节流函数,查看节流的效果。我的鼠标一直在div中移动,节流就会每个一段时间打印一次。

扒开面具见真相

对于我们而言,光知其然,是远远不够的;我们更要知其所以然! 老样子,咱们给自己上一课吧!

对于节流函数,与防抖的形参类似。它有三个参数:节流的执行函数fn;需要延迟的毫秒数wait;第三个参数options禁用第一次首先执行可以传递{leading: false},禁用最后一次执行{trailing: false}

那么根据第三个,可以传递两个属性参数。可能会出现三种情况:

  • 第一次先执行,最后一次不执行
  • 第一次不执行,最后一次执行
  • 第一次先执行,最后一次也执行

有头的

第一次先执行。

代码语言:javascript
复制
function throttle(fn, wait) {
  let previous = 0
  return function (...args) {
    let now = new Date().getTime() || Date.now()
    if (now - previous > wait) {
      fn.apply(this, args)
      previous = now
    }
  }
}

我们可以使用时间戳的方法去实现第一次触发先执行。先记录默认时间点(一开始为0),在执行函数时,求得当前的时间戳。两者间隔大于等待时间时,就执行fn函数。这样就能够保证第一次触发就能够先执行。 但是一定要将记录当前时间点的值赋给默认时间点,不然,鼠标移动时会一直触发函数执行。

2.gif

有尾巴的

在时间段尾部执行。

代码语言:javascript
复制
function throttle(fn, wait) {
  let timer = null
  return function (...args) {
    if (timer) return
    timer = setTimeout(() => {
      fn.apply(this, args)
      timer = null
    }, wait)
  }
}

考虑在尾部执行的情况。我们可以联想到定时器setTimeout,每隔一段时间触发执行一次。如果刚进来的话,正好在上一次执行的时间间隔内,就直接返回。只有当达到预定时间时(没有定时器,刚好要执行),执行函数,但是执行完成后一定要记得清空定时器,以免耽误下一次事件触发。

有头又有尾

嘿,这部就像我们做人一样嘛,有始有终! 根据第三个参数进行判断头尾。再把时间戳版和定时器版两者东拼拼西凑凑,大体模型就出来拉。

代码语言:javascript
复制
function throttle(fn, wait, options) {
  let previous = 0
  let timer = null
  return function (...args) {
        let now = Date.now()
        // 先执行
        // 先执行里面要判断leading情况
        if (!previous && options.leading === false) previous = now // 如果options.leading是后执行 在判断时间间隔时忽略
        if (now - previous > wait) {
          if (timer) {
            clearTimeout(timer)
            timer = null
          }
          fn.apply(this, args)
          previous = now
        }
        // 后执行
        if (!timer && options.trailing) { // 无定时器
          timer = setTimeout(() => {
            // 后执行里面要判断leading的情况
            previous = options.leading ? Date.now() : 0
            fn.apply(this, args)
            timer = null
          }, wait)
        }
      }
  console.log(previous);
}
let obtn = document.querySelector('#btn')
let obox = document.querySelector('.box')  // 按钮
function todo(e) {
  console.log(this, e);
}
let throttleFn = throttle(todo, 1000, { leading: false, trailing: false })
obox.onmousemove = throttleFn

加点装饰

上面已经算基本完成了节流的实现。此外,和防抖类似,还有执行函数有返回值的结果、取消节流的功能。

返回值的话,可以使用一个变量去接收执行函数返回值。取消节流在函数上添加一个取消功能函数(取消时清除定时器并且将一开始时间置0)。

代码语言:javascript
复制
function throttle(fn, wait, options) {
  let timer = null, previous = 0, result
  let throttled = function (...args) {
    let now = Date.now()
    if (!previous && options.leading == false) previous = now
    if (now - previous > wait) {
      if (timer) {
        clearTimeout(timer)
        timer = null
      }
      result = fn.apply(this, args)
      previous = now
    }
    if (!timer && options.trailing) {
      timer = setTimeout(() => {
        previous = options.leading ? Date.now() : 0
        result = fn.apply(this, args)
        timer = null
      }, wait);
    }
    return result
  }
  throttled.cancel = function () {
    if (timer) clearTimeout(timer)
    timer = null
    previous = 0
  }
  return throttled
}

如果需要同步结果可以使用promise,此处略过。

有什么用

节流的作用主要用于,在频繁触发某个事件的情况下,将其控制成一段时间请求一次。

  • 鼠标不断点击触发(单位时间内只触发一次)
  • 滚动监听,滚动到底部是否加载更多
  • input输入框输入监听(节流防抖都可)

节流防抖区别

防抖和节流都是减少用户调用频率。 防抖:一段时间内,鼠标一直不停地移动,以最后一次函数执行为准(后执行)。将多次触发,变为最后一次为准。 节流:一段时间执行函数,再过一段时间在执行函数。将多次触发,变为每隔一段时间触发。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 今天你敲代码了吗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 节流模样:
  • 扒开面具见真相
    • 有头的
      • 有尾巴的
        • 有头又有尾
          • 加点装饰
            • 有什么用
              • 节流防抖区别
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档