节流

# 使用 setTimeout 实现

  • 首次触发事件,不会执行回调
  • 停止触发事件,则 wait 时间过后还会执行一次回调
function throttle(fn, wait) {
  let timer = null
  let args = void 0
  return function () {
    args = arguments
    if (timer) return
    timer = setTimeout(() => {
      fn.apply(this, args)
      timer = null
    }, wait)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 不使用 setTimeout 实现

  • 第一次触发 fn 会立即执行
  • 最后一次触发事件之后,fn 不会再执行
function throttle(fn, wait) {
  let pre = 0
  return function () {
    let now = Date.now()
    if (now - pre >= wait) {
      pre = now
      fn.apply(this, arguments)
    }
  }
}
1
2
3
4
5
6
7
8
9
10

# 结合实现

// 优化:组合上述两种方式
// 两者不能同时为false
// options: {
//   leading:false 表示禁用第一次执行
//   trailing: false 表示禁用停止触发的回调
// }
function throttle(fn, wait, options) {
  let pre = 0
  let timer = null
  let args
  let context = null
  options = options || {}

  let later = () => {
    // 如果设置了禁用第一次执行
    pre = options.leading === false ? 0 : Date.now()
    timer = null
    fn.call(context, args)
  }

  return function () {
    args = arguments
    context = this
    let now = Date.now()
    // 如果是第一次触发,并且禁用第一次执行
    if (!pre && options.leading === false) pre = now
    // 计算距离下一次执行的剩余时间
    let remaining = wait - (now - pre)
    // 如果到了执行的时间了
    if (remaining <= 0) {
      // 先判断有没有正在运行的定时器,没有的话直接执行
      if (!timer) {
        // 更新执行时间
        pre = now
        fn.call(this, ...arguments)
      } else {
        clearTimeout(timer)
        timer = null
      }
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Last Updated: 10/21/2024, 4:15:17 PM