带你“深入”节流

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

网络异常,图片无法展示
|


说白话:


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

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


网络异常,图片无法展示
|


说人话:


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


节流模样:


<!-- <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>

网络异常,图片无法展示
|


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


扒开面具见真相


对于我们而言,光知其然,是远远不够的;我们更要知其所以然!

老样子,咱们给自己上一课吧!


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


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

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


有头的


第一次先执行。


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函数。这样就能够保证第一次触发就能够先执行。


但是一定要将记录当前时间点的值赋给默认时间点,不然,鼠标移动时会一直触发函数执行。


网络异常,图片无法展示
|


有尾巴的


在时间段尾部执行。


function throttle(fn, wait) {
  let timer = null
  return function (...args) {
    if (timer) return
    timer = setTimeout(() => {
      fn.apply(this, args)
      timer = null
    }, wait)
  }
}


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


网络异常,图片无法展示
|


有头又有尾


嘿,这部就像我们做人一样嘛,有始有终!


根据第三个参数进行判断头尾。再把时间戳版和定时器版两者东拼拼西凑凑,大体模型就出来拉。

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)。


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输入框输入监听(节流防抖都可)


节流防抖区别


防抖和节流都是减少用户调用频率。


防抖:一段时间内,鼠标一直不停地移动,以最后一次函数执行为准(后执行)。将多次触发,变为最后一次为准。


节流:一段时间执行函数,再过一段时间在执行函数。将多次触发,变为每隔一段时间触发。


赠言


做人如果没有梦想,那跟咸鱼有什么区别啊!

网络异常,图片无法展示
|

目录
相关文章
节流
【10月更文挑战第17天】
|
6月前
节流、防抖
节流、防抖
44 2
|
6月前
|
前端开发 UED
关于防抖和节流的理解
防抖和节流是前端开发中常用的两种性能优化技术。
37 0
防抖&节流
防抖&节流
117 0
什么是防抖和节流,怎么实现一个防抖和节流?
功能:当事件被触发N秒之后再执行回调,如果在N秒内被触发,则重新计时。
|
JavaScript 前端开发
节流与防抖
节流与防抖
51 0
|
前端开发
什么是防抖和节流?有什么区别?
什么是防抖和节流?有什么区别?
81 0
|
JavaScript 前端开发
什么是防抖和节流?如何实现防抖和节流?
防抖(debounce)和节流(throttle)是 JavaScript 中常用的两种性能优化方法。