# 防抖 debounce

# 介绍

事件触发一段时间后才会调用,频繁触发只会在最后一次执行。一般使用在搜索联想

# 实现

/**
 * @desc 函数防抖
 * @param {Function} callback 回调函数
 * @param {Number} wait 延迟毫秒数
 * @param {Boolean} immediate 立即执行
 * 
 * @return {Function}
 */
const debounce = (callback, wait = 300, immediate = false) => {
  let timer
  return function () {
    let ctx = this
    let args = arguments

    if (timer) {
      clearTimeout(timer)
    }

    if (immediate) {
      let callNow = !timer
      timer = setTimeout(() => {
        timer = null
      }, wait)
      if (callNow) {
        callback.apply(ctx, args)
      }
    } else {
      timer = setTimeout(() => {
        callback.apply(ctx, args)
      }, wait)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 节流 throttle

# 介绍

连续触发事件,但在一段时间内只触发一次。一般使用在resize、touchmove,无限加载等。

防止表单提交按钮被多次触发,我们应该选择使用节流而不是防抖方案,秒杀抢购等业务场景。

# 实现

/**
 * @desc 函数节流 时间戳版本
 * @param callback 函数
 * @param wait 延迟执行毫秒数
 */
const throttle = (callback, wait) => {
  let prev = Date.now()
  return function () {
    let context = this
    let args = arguments
    let now = Date.now()

    if (now - prev >= wait) {
      callback.apply(context, args)
      prev = now
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 * @desc 函数节流 定时器版本
 * @param callback 函数
 * @param wait 延迟执行毫秒数
 */
const throttle = (callback, wait) => {
  let timer = null
  return function () {
    let context = this
    let args = arguments
    if (!timer) {
      timer = setTimeout(() => {
        callback.apply(context, args)
        timer = null
      }, wait)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 * @desc 函数节流 结合
 * @param callback 函数
 * @param wait 延迟执行毫秒数
 */
const throttle = (callback, wait) => {
  let timer = null
  let prev = Date.now()
  return function () {
    let curTime = Date.now()
    let remaining = wait - (curTime - prev)
    let context = this
    let args = arguments
    // 取消定时器,重新计算remaining
    clearTimeout(timer)
    if (remaining <= 0) {
      // 第一次触发立即执行处理函数
      callback.apply(context, args)
      prev = Date.now()
    } else {
      // 没到时间,最后一次触发还能执行处理函数
      timer = setTimeout(callback, remaining)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25