防抖(debounce)& 节流(throttle)

简介: 防抖(debounce)& 节流(throttle)

image.png


一、概念

作用:【防抖】和【节流】的作⽤都是防⽌某个函数被多次调⽤.

区别:假设⽤户⼀直触发某个函数,且每次触发函数的间隔⼩于期望时间 【wait】,【防抖】的情况下只会调⽤【⼀次】,⽽【节流】的情况下会每隔⼀定时间【wait】调⽤函数。

PS:防抖动和节流本质是不⼀样的。防抖动是将多次执⾏变为最后⼀次执⾏,节流是将多次执⾏变成每隔⼀段时间执⾏.

二、防抖 - debounce

PS:防抖函数,返回函数连续调⽤时,空闲时间必须 >= wait,func 才会执⾏.

1. 防抖的简单实现

/**
     * @param  {function}   func   传入的回调函数
     * @param  {number}     wait   期望时间
     * @return {function}          返回包装的函数
     * */ 
    function debounce(func, wait = 50) {
      let timer = null;
      // 利用闭包保存变量,否则函数一执行完之后,变量就被初始化
      return function (...params) {
        // 如果已经设定过定时器了就清空上⼀次的定时器
        // 否则当前函数被多次触发时,就会存在多个定时器,那么当前函数也会被多次执行
        if (timer) {
          clearTimeout(timer);
        }
        // 开始⼀个新的定时器
        timer = setTimeout(() => {
          func.apply(null, params);
        }, wait);
      }
    }
复制代码

以上的实现方式拥有缺陷:

  • 如果⽤户调⽤该函数的间隔⼩于 wait 的情况下,上⼀次定时器的时间还未到就被清除了,并不会去执⾏函数
  • 防抖函数只能在最后的时刻被调⽤.⼀般的防抖会有 immediate 选项,表示是否⽴即调⽤。

2. 防抖实现(包含 immediate 功能)

/*
     * @param {function}  func      回调函数
     * @param {number}    wait      期望时间间隔
     * @param {boolean}   immediate 设置为 ture 时,会⽴即调⽤函数
     * @return {function}           返回客户调⽤函数
     */
    function debounce(func, wait = 50, immediate) {
      let timer = null;
      let context, args;
      // 抽成 later 函数是为了方便多次执行,不需要重复声明
      const later = () => setTimeout(() => {
        // 延迟函数执⾏完毕,清空缓存的定时器序号
        timer = null;
        // 如果已经需要立即执行,那么就不需要在延迟执行一次
        if (!immediate) {
          func.apply(context, args);
        }
        // 手动进行垃圾回收
        context = args = null;
      }, wait);
      return function (...params) {
        // 1.未创建延迟函数,先创建
        if (!timer) {
          timer = later();
          // 1.1需要立即执行一次,就直接执行
          if (immediate) {
            func.apply(this, params);
          } else {
            // 1.2不需要立即执行,保存当前 this 和 入参 args,保证在 later 函数执行时回调函数 func 的正确执行
            context = this;
            args = params;
          }
        } else {
          // 2. 延迟函数已执行
          // 2.1 先清除原来的并重新设定⼀个
          clearTimeout(timer);
          // 2.2 保证重新计时
          timer = later();
        }
      }
    }
复制代码

三、节流 - throttle

/**
     * 节流函数,返回函数连续调⽤时,func 执⾏频率限定为【次 / wait】
     *
     * @param {function}   func    回调函数
     * @param {number}     wait    表示时间的间隔
     * @return {function}          返回客户调⽤函数 
     */
    function throttle(func, wait = 50, options) {
      let timer = null;
      let result;
      let previous = 0;
      return function (...args) {
        // 每次执行函数,先保存当前时间
        let now = +new Date();
        // 计算剩余时间
        let remaining = wait - (now - previous);
        // remaining <= 0   代表首次执行
        // remaining > wait 代表定时器比预期执行时更晚,但也符合执行时机
        if (remaining <= 0 || remaining > wait) {
          // 如果存在定时器就清理掉否则会调⽤⼆次回调
          if (timer) {
            clearTimeout(timer);
            timeout = null;
          }
          // 执行函数时,把当前时间,记录为上一次执行时间
          previous = now;
          result = func.apply(this, args);
        } else if (!timer) {
        // 判断是否设置了定时器
        // 没有的话就开启⼀个定时器
          timer = setTimeout(() => {
            // 执行函数时,把当前时间,记录为上一次执行时间
            // 由于这里是异步的,所以不能直接使用 now,必须要重新获取时间
            previous = +new Date();
            result = func.apply(this, args);
          }, remaining); 
        }
        // 返回结果值
        return result;
      }
    }


目录
相关文章
|
2月前
|
前端开发 JavaScript UED
|
6月前
节流、防抖
节流、防抖
44 2
|
6月前
uView throttle & debounce节流防抖
uView throttle & debounce节流防抖
122 0
|
6月前
|
前端开发 UED
关于防抖和节流的理解
防抖和节流是前端开发中常用的两种性能优化技术。
37 0
|
11月前
|
监控
throttle和debounce
throttle和debounce
79 1
防抖&节流
防抖&节流
117 0
|
JavaScript 前端开发
节流与防抖
节流与防抖
51 0
|
前端开发 JavaScript
关于防抖和节流我所知道的
关于防抖和节流我所知道的
61 0