Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【20190902】防抖和节流函数 #109

Open
zhongxia245 opened this issue Sep 2, 2019 · 1 comment
Open

【20190902】防抖和节流函数 #109

zhongxia245 opened this issue Sep 2, 2019 · 1 comment
Labels

Comments

@zhongxia245
Copy link
Owner

zhongxia245 commented Sep 2, 2019

一、What?

防抖函数(debounce) :某个函数在某段时间内,无论触发了多少次回调,都只执行最后一次

函数节流(throttle) :某个函数在一定时间间隔内(例如 3 秒)只执行一次,在这 3 秒内 无视后来产生的函数调用请求,也不会延长时间间隔。

简单来说
防抖函数:一个是延迟多久触发
节流函数:一个是多久触发一次
引用:lessfish/underscore-analysis#20 (comment)

二、When?

防抖函数:

  1. autocomplete组件,文本框输入内容后,提示相关内容
  2. 每次 resize/scroll 触发统计事件
  3. 文本输入的验证(连续输入文字后发送 AJAX 请求进行验证,验证一次就好)

节流函数:

  1. 监听滚动事件判断是否到页面底部自动加载更多
  2. DOM 元素的拖拽功能实现(mousemove)
  3. 射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
  4. Canvas 模拟画板功能(mousemove)

三、How?

这两个函数,是闭包的应用,它会返回一个新的函数。

因此,使用方式如下

// 执行 debounce 函数返回新函数
const betterFn = debounce(() => console.log('fn 防抖执行了'), 1000)
// 停止滑动 1 秒后执行函数 () => console.log('fn 防抖执行了')
document.addEventListener('scroll', betterFn)

// 执行 throttle 函数返回新函数
const betterFn = throttle(() => console.log('fn 函数执行了'), 1000)
// 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fn
setInterval(betterFn, 10)

四、常见问题

1. React 中,如果类似这样使用防抖函数,会获取input 的值,因为 e.target 为空

<input  type="text" onChange={debounce(this.onChange, 300)} />

// 解决方案
class mime extends Component {
  constructor(props) {
    super(props);
    this.state = {};

    this.onGetData = debounce(this.onGetData, 300);
  }

  onGetData = (val) => {
    console.log(`getData By :${val}`);
  };

  onChange = (e) => {
    this.onGetData(e.target.value);
  };

  render() {
    return (
      <div>
        <h1>防抖函数的在 react 中的应用</h1>
        <input
          type="text"
          onChange={this.onChange}
        />
      </div>
    );
  }
}

终、参考文章

1、 《【进阶 6-4 期】深入浅出防抖函数 debounce》
2、《在 react 组件中使用 debounce 函数》

@zhongxia245
Copy link
Owner Author

zhongxia245 commented Sep 2, 2019

简单的防抖,节流函数的实现,面试中,可能让你手写这两个方法,因此需要自己理解下原理,然后敲一两遍,加深记忆。(看了都懂,听了都会,上手全废)

/**
 * 【简单版】防抖函数
 * 使用 setTimeout 和 clearTimeout 来实现
 * @param {function} fn 需要防抖的函数
 * @param {number} wait 防抖的等待时间
 */
const debounce = (fn, wait = 100) => {
  // 通过闭包记录浏览器标识
  let timer = null

  // 通过防抖处理,会返回一个新的函数
  return function(...args) {
    // 已经设置过定时器,则清空上一次的定时器,重新开始计时
    if (timer) clearTimeout(timer)

    // 设定一个新的定时器,定时器结束后开始执行传入的函数
  timer =   setTimeout(() => {
      fn.apply(this, args)
    }, wait)
  }
}

/**
 * 增加立即执行的防抖函数
 * @param {function} fn 需要防抖的函数
 * @param {number} wait 防抖的等待时间
 * @param {bool} immediate 是否立即执行
 */
const debounce1 = (fn, wait = 100, immediate = false) => {
  let timer = null
  return function(...args) {
    if (timer) clearTimeout(timer)

    // 放开始立即执行一次, 定时器未空的时候,就是第一次。
    if (immediate && !timer) {
      fn.apply(this, args)
    }

 timer =   setTimeout(() => {
      fn.apply(this, args)
    }, wait)
  }
}

/**
 * 【简单版】函数节流
 * @param {function} fn 需要防抖的函数
 * @param {number} wait 节流的等待时间
 */
const throttle = (fn, wait = 100) => {
  // 通过闭包记录开始时间
  let start = 0
  return function(...args) {
    let now = Date.now()

    // 当前时间减去开始时间,大于间隔的时间,则执行函数
    if (now - start > wait) {
      start = now
      fn.apply(this, args)
    }
  }
}

/**
 * 函数节流
 * 触发时间如果小于间隔时间,则使用防抖来执行函数
 * @param {function} fn 需要防抖的函数
 * @param {number} wait 节流的等待时间
 */
const throttle1 = (fn, wait = 100) => {
  // 通过闭包记录开始时间
  let start = 0
  let timer = null
  return function(...args) {
    let now = Date.now()

    // 当前时间减去开始时间,大于间隔的时间,则执行函数
    if (now - start > wait) {
      start = now
      fn.apply(this, args)
    } else {
      // 解决用户最后一次操作距离上一次触发时间的时长打不到 wait 时长,为用户的最后一次操作进行兜底
      if (timer) clearTimeout(timer)

      timer = setTimeout(() => {
        start = now
        fn.apply(this, args)
      }, wait)
    }
  }
}

@zhongxia245 zhongxia245 changed the title 【20190902】函数防抖和节流 【20190902】防抖和节流函数 Sep 2, 2019
@zhongxia245 zhongxia245 added the JS label Sep 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant