实现原理就是利用定时器,函数第一次执行时设定一个定时器,之后调用时发现已经设定过定时器就清空之前的定时器,并重新设定一个新的定时器,如果存在没有被清空的定时器,当定时器计时结束后触发函数执行。

手写一个 debounce

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

// fn 是需要防抖处理的函数
// wait 是时间间隔
function debounce(fn, wait = 50) { // 通过闭包缓存一个定时器 id let timer = null // 将 debounce 处理结果当作函数返回 // 触发事件回调时执行这个返回函数 return function(...args) { // this保存给context const context = this // 如果已经设定过定时器就清空上一次的定时器 if (timer) clearTimeout(timer) // 开始设定一个新的定时器,定时器结束后执行传入的函数 fn timer = setTimeout(() => { fn.apply(context, args) }, wait) }
} // DEMO
// 执行 debounce 函数返回新函数
const betterFn = debounce(() => console.log('fn 防抖执行了'), 1000)
// 停止滑动 1 秒后执行函数 () => console.log('fn 防抖执行了')
document.addEventListener('scroll', betterFn) 

不过 underscore 中的 debounce 还有第三个参数:immediate 。这个参数是做什么用的呢?

传参 immediate 为 true, debounce会在 wait 时间间隔的开始调用这个函数 。(注:并且在 wait 的时间之内,不会再次调用。)在类似不小心点了提交按钮两下而提交了两次的情况下很有用。

把 true 传递给 immediate 参数,会让 debounce 在 wait 时间开始计算之前就触发函数(也就是没有任何延时就触发函数),而不是过了 wait 时间才触发函数,而且在 wait 时间内也不会触发(相当于把 fn 的执行锁住)。如果不小心点了两次提交按钮,第二次提交就会不会执行。

那我们根据 immediate 的值来决定如何执行 fn 。如果是 immediate 的情况下,我们立即执行 fn ,并在 wait 时间内锁住 fn 的执行, wait 时间之后再触发,才会重新执行 fn ,以此类推。

// immediate 表示第一次是否立即执行
function debounce(fn, wait = 50, immediate) { let timer = null return function(...args) { // this保存给context const context = this if (timer) clearTimeout(timer) // immediate 为 true 表示第一次触发后执行 // timer 为空表示首次触发 if (immediate && !timer) { fn.apply(context, args) } timer = setTimeout(() => { fn.apply(context, args) }, wait) }
} // DEMO
// 执行 debounce 函数返回新函数
const betterFn = debounce(() => console.log('fn 防抖执行了'), 1000, true)
// 第一次触发 scroll 执行一次 fn,后续只有在停止滑动 1 秒后才执行函数 fn
document.addEventListener('scroll', betterFn)

underscore 源码解析

看完了上文的基本版代码,感觉还是比较轻松的,现在来学习下 underscore 是如何实现 debounce 函数的,学习一下优秀的思想,直接上代码和注释,本源码解析依赖于 underscore 1.9.1 版本实现。

// 此处的三个参数上文都有解释
_.debounce = function(func, wait, immediate) { // timeout 表示定时器 // result 表示 func 执行返回值 var timeout, result; // 定时器计时结束后 // 1、清空计时器,使之不影响下次连续事件的触发 // 2、触发执行 func var later = function(context, args) { timeout = null; // if (args) 判断是为了过滤立即触发的 // 关联在于 _.delay 和 restArguments if (args) result = func.apply(context, args); }; // 将 debounce 处理结果当作函数返回 var debounced = restArguments(function(args) { if (timeout) clearTimeout(timeout); if (immediate) { // 第一次触发后会设置 timeout, // 根据 timeout 是否为空可以判断是否是首次触发 var callNow = !timeout; timeout = setTimeout(later, wait); if (callNow) result = func.apply(this, args); } else { // 设置定时器 timeout = _.delay(later, wait, this, args); } return result; }); // 新增 手动取消 debounced.cancel = function() { clearTimeout(timeout); timeout = null; }; return debounced;
}; // 根据给定的毫秒 wait 延迟执行函数 func
_.delay = restArguments(function(func, wait, args) { return setTimeout(function() { return func.apply(null, args); }, wait);
}); 

相比上文的基本版实现,underscore 多了以下几点功能。

  1. 1、函数 func 的执行结束后返回结果值 result
  1. 2、定时器计时结束后清除 timeout ,使之不影响下次连续事件的触发
  1. 3、新增了手动取消功能 cancel
  1. 4、immediate 为 true 后只会在第一次触发时执行,频繁触发回调结束后不会再执行

防抖函数Debounce实现相关推荐

  1. debounce实现 js_javascript防抖函数debounce详解

    定义及解读 防抖函数 debounce 指的是某个函数在某段时间内,无论触发了多少次回调,都只执行最后一次.假如我们设置了一个等待时间 3 秒的函数,在这 3 秒内如果遇到函数调用请求就重新计时 3 ...

  2. 手把手教你实现一个防抖函数(debounce)

    前言:防抖函数在日常开发中属于是一个非常非常重要的知识点.通常在一个项目的最开始构建的时候,都会在 utils文件夹下备上这样一个函数,来为以后做准备. (tips:utils 在大部分翻译软件内好像 ...

  3. 防抖c语言,花式解说防抖函数debounce的实现

    歪式絮叨:原本打算只用一篇文章总结下防抖和节流的,但是写着写着发现挺有意思的.所以准备会分成 3-4 篇来写了,单独的防抖和节流的实现,然后在去分享一下知名库的源码.今天先跟歪马一起看看防抖的实现吧. ...

  4. java接口防抖_花式解说防抖函数debounce的实现

    歪式絮叨:原本打算只用一篇文章总结下防抖和节流的,但是写着写着发现挺有意思的.所以准备会分成 3-4 篇来写了,单独的防抖和节流的实现,然后在去分享一下知名库的源码.今天先跟歪马一起看看防抖的实现吧. ...

  5. Vue中封装使用防抖函数

    一.封装防抖函数 debounce(fn, time) {let timer = null;return function(...args) {let _this = this;if(timer) { ...

  6. 详解防抖函数(debounce)和节流函数(throttle)

    函数防抖(debounce) 函数防抖,就是指触发事件后,在 n 秒后只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数的执行时间. 简单的说,当一个动作连续触发,只执行最后一次. 列举: ...

  7. debounce实现 js_js 实现一个debounce防抖函数

    debounce是指当函数被触发时,如果没有到我们设定的时间,函数不会执行,如果在设定时间之前多次触发,那么计时器会被重设,直到最后一次触发后过了设定的时间,函数才会真正执行. 一般的应用场景是:in ...

  8. windows 改变文件大小 函数_手写 bind call apply 方法 与 实现节流防抖函数

    实现 bind call apply 方法 this 是什么? this是指包含它的函数作为方法被调用时所属的对象.这句话理解起来感觉还是很拗口的,但是如果你把它拆分开来变成这三句话后就好理解一点了. ...

  9. vue中的防抖函数写法

    vue中的methods // 防抖方法debounce(func,delay){let timer=nullreturn function (...args) {timer && c ...

最新文章

  1. linux内核内存管理(zone_dma zone_normal zone_highmem)
  2. Glossary in Turbulence
  3. Volley源码分析
  4. 使用MASM02 - Win32汇编语言010
  5. ABAP Range
  6. Unity(一)Unity脚本程序开发
  7. 过山车(HDU-2063)
  8. UIPickView 和 UIDatePicker
  9. C#使用百度API通过IP获取地理位置和坐标
  10. Win11系统如何打开地雷游戏 Win11打开扫雷游戏的教程
  11. 使用QGIS将文本坐标转换为矢量文件
  12. Android如何实现音频输出路由的切换
  13. 解决在使用pip进行安装时的Could not install packages due to an EnvironmentError的问题
  14. UEFI规范实现EDKII项目学习笔记绪论[0]
  15. C#基础视频教程5.2 如何编写简单的超级热键
  16. (电力开发)376.1 主站通信协议基本结构解析
  17. 联合索引的最左匹配原则的成因
  18. 使用r语言进行excel表格的分类与汇总
  19. iOS7+系统自带条码扫描
  20. 网络设计:搭建校园网(组网工程课设)【译】

热门文章

  1. 程序员崩溃的10个瞬间
  2. 闭包的介绍、构成条件、作用及示例代码
  3. 线性回归之案例:波士顿房价预测
  4. schema.sql自动写入。由于版本问题。2.x之后。就不行了。·
  5. 动态多尺度图表达3D人体骨架运动,实现精准预测效果超SOTA
  6. 使用OpenCV实现图像增强
  7. 你不知道的车牌识别系统
  8. 详解通用物体检测算法:基于锚框与无需锚框
  9. 第二篇:n-gram 语言模型
  10. 卸载系统预装McAfee Agent