亮神知识库 亮神知识库
首页
  • 手写代码

    • 手写代码系列
  • 基础知识

    • 基础
    • JS底层
    • CSS
  • 原理
  • 浏览器
  • HTTP
  • 网络安全
  • babel
  • webpack基础
  • webpack进阶
  • Vite
  • TypeScript
  • Vue2
  • Vue3
  • Node基础

    • glob
    • 模块化机制
    • 事件循环
    • KOA2框架原理
    • Node子进程
    • cluster原理(了解)
  • 教育行业2021

    • B端
    • C端
    • 工具
  • 游戏行业2025
  • 刷题
  • 杂(待整理)
  • 学习
  • 面试
  • 实用技巧
  • 心情杂货
  • 年度总结
  • 友情链接
关于
  • 分类
  • 标签
  • 归档
  • 收藏
GitHub (opens new window)

亮神

前程明亮,未来可期
首页
  • 手写代码

    • 手写代码系列
  • 基础知识

    • 基础
    • JS底层
    • CSS
  • 原理
  • 浏览器
  • HTTP
  • 网络安全
  • babel
  • webpack基础
  • webpack进阶
  • Vite
  • TypeScript
  • Vue2
  • Vue3
  • Node基础

    • glob
    • 模块化机制
    • 事件循环
    • KOA2框架原理
    • Node子进程
    • cluster原理(了解)
  • 教育行业2021

    • B端
    • C端
    • 工具
  • 游戏行业2025
  • 刷题
  • 杂(待整理)
  • 学习
  • 面试
  • 实用技巧
  • 心情杂货
  • 年度总结
  • 友情链接
关于
  • 分类
  • 标签
  • 归档
  • 收藏
GitHub (opens new window)
  • 基础

  • 手写代码

    • 手写类型转换
    • 手写累加、累乘函数
    • 手写new
    • 手写深拷贝
    • 手写Object.create
    • 手写继承
    • 手写extends
    • 手写instanceof
    • 手写call、apply、bind
    • 手写jsonp
    • 手写getQueryString
    • 手写setInterval
    • 手写防抖与节流
      • debounce 防抖
      • throttle 节流
        • 方法一:使用时间差
        • 方法二:使用定时器
      • 节流优化(待整理)
    • 手写对象属性值迭代器
    • 手写分时函数
    • 手写事件委托
    • 手写图片懒加载
    • 手写原生Ajax请求
    • 手写AOP装饰函数
    • 手写柯里函数
    • 手写数组扁平化flat
    • 手写数组去重
    • 手写eventEmit类
    • 手写Vue数据响应式
    • 手写Vue nextTick
    • 手写Promise
  • JS底层深入

  • CSS

  • 基础
  • 手写代码
0zcl
2021-06-18
目录

手写防抖与节流

  • 防抖:点击之后,必须隔一段,再点击才会生效。时间无论持续触发了多少次事件,都只执行最后一次
  • 节流:持续触发事件,隔一段时间执行一次

防抖和节流会返回 <code>防抖函数</code> 和 <code>节流函数</code>

# debounce 防抖

注意

实现一个防抖

function debounce(func, wait, immediate) {
  let timer = null
  // 防抖函数. 注意:这里用箭头函数的话,箭头函数没有自己的arguments
  return function() {
    const args = [...arguments]
    // 持续触发时,不执行。就算clearTimeout,timer依旧会存在!
    if (timer) clearTimeout(timer)
    // 立即执行
    if (immediate && !timer) {
      func.apply(this, args)
    }

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

// 测试
var debounceFn = debounce((...args) => console.log('防抖函数', args), 1000, true)
document.addEventListener('scroll', debounceFn)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

注意:

  1. debounce返回的是防抖函数。
  2. 防抖函数的this指向(推调用防抖函数this指向谁),传参,返回值
  3. immediate, 立即执行防抖函数
  4. cancel, 取消防抖, 再去触发,又可以立刻执行
function debounce(func, wait, immediate) {
  let timer = null
  // 防抖函数. 注意:这里用箭头函数的话,箭头函数没有自己的arguments
  const debounced = function() {
    const args = [...arguments]
    // 持续触发时,不执行。就算clearTimeout,timer依旧会存在!
    if (timer) clearTimeout(timer)
    // 第一闪,立即执行
    if (immediate && !timer) {
      return func.apply(this, args)
    }

    timer = setTimeout(() => {
      return func.apply(this, args)
    }, wait)
  }
  // 执行cancel后,再触发,第一次会立即执行
  debounced.cancel = function() {
    clearTimeout(timer)
    timer = null
  }
  return debounced
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# throttle 节流

注意

实现一个节流

# 方法一:使用时间差

function throttle(func, wait) {
  let previous = 0
  return function() {
    const args = [...arguments]
    let now = new Date().getTime()
    // 当鼠标移入的时候,事件立刻执行
    if (now - previous > wait) {
      previous = new Date().getTime()
      return func.apply(this, args)
    }
  }
}

// 测试
var throttleFn = throttle((...args) => console.log('防抖函数', args), 1000)
document.addEventListener('scroll', throttleFn)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

throttle_1

我们可以看到:当鼠标移入的时候,事件立刻执行,每过 1s 会执行一次,如果在 4.2s 停止触发,以后不会再执行事件

# 方法二:使用定时器

function throttle(func, wait) {
  let timer = null
  return function() {
    if (!timer) {
      const args = [...arguments]
      timer = setTimeout(() => {
        timer = null
        return func.apply(this, args)
      }, wait)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

throttle_2

当鼠标移入的时候,事件不会立刻执行,晃了 3s 后终于执行了一次,此后每 3s 执行一次,当数字显示为 3 的时候,立刻移出鼠标,相当于大约 9.2s 的时候停止触发,但是依然会在第 12s 的时候执行一次事件

<strong>时间戳方法,有头无尾;定时器方法,有尾无头</strong>

# 节流优化(待整理)

在 <code>underscore</code> 中的节流函数, 默认是有头有尾的。即:鼠标移入能立刻执行,停止触发的时候还能再执行一次!

战术放弃!

参考: JavaScript专题之跟着 underscore 学节流 (opens new window) 深入浅出节流函数 (opens new window)

编辑 (opens new window)
上次更新: 2025/07/20, 06:21:22
手写setInterval
手写对象属性值迭代器

← 手写setInterval 手写对象属性值迭代器→

最近更新
01
2024年
07-20
02
2023年
07-20
03
2022年
07-20
更多文章>
Theme by Vdoing | Copyright © 2025-2025 亮神 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式