资讯专栏INFORMATION COLUMN

JS专题之去抖函数

ivydom / 1469人阅读

摘要:如果本次定时器没有被清除,时间到后就会自然执行事件处理函数。绑定去抖后的事件回调函数绑定回调函数的属性方法,点击页面,重置去抖效果异步请求清空上一次事件触发的定时器重置为从而下一次事件触发就能立即执行。

一、前言

为什么会有去抖和节流这类工具函数?

在用户和前端页面的交互过程中,很多操作的触发频率非常高,比如鼠标移动 mousemove 事件, 滚动条滑动 scroll 事件, 输入框 input 事件, 键盘 keyup 事件,浏览器窗口 resize 事件。

在以上事件上绑定回调函数,如果回调函数是一些需要大量计算、消耗内存、HTTP 请求、DOM 操作等,那么应用的性能和体验就会非常的差。

去抖和节流函数的根据思想就是,减少高频率事件处理函数 handler 的执行频率(注意是事件处理函数,不是事件回调函数),将多次事件的回调合并成一个回调来执行,从而优化性能。

二、简单版去抖(debounce)

去抖(debounce),也叫防抖,那抖动指的是什么呢?抖动意味着操作的不稳定性,你可以理解成躁动症,安静不下来~防抖的含义便是为了防止抖动造成的结果不准确,等到稳定的时候再处理结果。

比如在输入事件,鼠标移动,滚动条滑动,键盘敲击事件中,等到停止事件触发,频率稳定为零后,才开始执行回调函数,也就是所谓的没有抖动后处理。

个人总结:去抖,就是事件触发频率稳定后,才开始执行回调函数, 一连串的事件触发,但只进行一次事件处理。

频率就是单位时间触发的次数,如果单位时间内,事件触发超过一次,就只执行最后一次,如果单位时间内没有触发超过一次,那就正常执行。去抖分为延迟执行和立即执行两种思路。

看一个简单版的去抖函数延迟执行实现:

输入框:

上面代码中我的注释已经能够说明整个去抖的过程,再来啰嗦几句话~

debounce 函数在主线程顺序执行时已经被调用,传入的参数一个是真正想在事件触发执行的事件处理函数

另一个参数是事件触发的间隔时间,间隔时间内再次触发事件,则重新计时,类似于罚你 5 分钟内不准说话,时间到后就可以开始说话,如果 5 分钟内说话了,则再罚你 5 分钟内不准说话,以此类推~

debounce 函数有一个 timer 内部变量,timer 在返回的执行函数中被访问,形成了闭包,有关闭包的内容,可以翻看我之前的文章《JavaScript之闭包》

bebounce 函数返回的匿名函数才是 input 事件的回调函数,所以该匿名函数有一个默认参数 event 对象。

同第 4 点,匿名函数是 dom 元素注册事件的回调函数,所以匿名函数(回调函数)的 this 指向 HTMLInput 元素。

同第 2 点,触发函数后,如果发现闭包中保存着 timer 变量, timer 变量初始值为 null, 之后触发定时器后,timer 为当次定时器的 id,id 是一个数字。去抖的过程在于,如果在定时器的间隔时间内触发了函数,它会把上一次事件触发时定义的定时器清除,又重新定义一个定时器。如果本次定时器没有被清除,时间到后就会自然执行事件处理函数。对这个过程有困惑的同学,可以把 timer 变量在 clearTimeout 之前打印出来就明白了。

延时执行了事件处理函数(handler),需要传递调用对象和事件对象过去,此处 call 可以和 apply 互换,如果用 apply, 传递 arguments 类数组即可。这样保证了参数的一致性,就像没被 debounce 处理过一样。

以上就是去抖函数的基本思想, 可以参考示意图

下面这张图是高设 3 里讲的节流函数,其实是这一节所说的去抖函数,高设 3 将 timer 变量用传入的处理函数的属性代替了而已。

三、立即执行

第二节的简单版去抖函数能满足大部分只需要触发一次事件处理的去抖场景:输入数据查询事件,下拉滚动条到窗口底部懒加载数据。

但是有一个问题,假如我想输入框输入内容时,第一个字输完就请数据怎么做? 你可以理解为,你可以马上开始说话,但是说完话后 5 分钟不能说话,如果 5 分钟内说话,则接下来再加 5 分钟不能说话。如果 5 分钟后没说话, 那么接下来,你又可以先说话,然后闭嘴 5 分钟~

所以,引出来了立即执行版的去抖函数。

取消功能实现

输入框:

上面代码的注释,可以解释整个流程,下面大致说一下:

非立即执行版本和前一节内容一样,跳过。

timer 初始值为 null, 第一次触发为立即执行,!timer 为 true, 所以能够立即调用事件处理函数。

每次事件触发, 都会把 timer 重新赋值,在间隔时间到之前 timer 为数字 id, !timer 为 false, 所以不能立即执行。如果间隔时间到了,会把当次事件触发的定时器 id 置为 null, 下一次事件触发就能立即执行了。

朋友们可以通过观察 timer 值的变化,思考整个过程,timer 在去抖的过程中充当 flag 的作用,可以用来判断能否立即执行。

看看效果:

取消函数

假如去抖函数的间隔时间为 5 秒钟,我在这 5 秒钟内又想立即执行可以怎么做?于是我们给回调函数加个取消函数属性。

函数也是一个对象,可以像其他一般对象那样添加方法:

输入框:

看看效果:

总结

去抖函数的意义在于合并多次事件触发为一次事件处理,从而降低事件处理函数可能引发的大量重绘重排,http 请求,内存占用和页面卡顿。

另外,本文有关 this, call, apply,闭包的知识,可以翻看我之前分享的文章。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99829.html

相关文章

  • JS专题之数组去重

    摘要:将元素作为对象的键,默认键对应的值为如果对象中没有这个键,则将这个元素放入结果数组中去。 前言 数组去重在日常开发中的使用频率还是较高的,也是网上随便一抓一大把的话题,所以,我写这篇文章目的在于归纳和总结,既然很多人都在提的数组去重,自己到底了解多少呢。又或者是如果自己在开发中遇到了去重的需求,自己能想到更好的解决方案吗。 这次我们来理一理怎么做数组去重才能做得最合适,既要考虑兼容性,...

    only_do 评论0 收藏0
  • JS专题之节流函数

    摘要:一什么是节流节流函数就是让事件处理函数在大于等于执行周期时才能执行,周期之内不执行,即事件一直被触发,那么事件将会按每小段固定时间一次的频率执行。我们通过一个简单的示意来理解节流函数可以用时间戳和定时器两种方式进行处理。 本文共 2000 字,读完只需 8 分钟 上一篇文章讲了去抖函数,然后这一篇讲同样为了优化性能,降低事件处理频率的节流函数。 一、什么是节流? 节流函数(thrott...

    huaixiaoz 评论0 收藏0
  • JavaScript专题系列文章

    摘要:专题系列共计篇,主要研究日常开发中一些功能点的实现,比如防抖节流去重类型判断拷贝最值扁平柯里递归乱序排序等,特点是研究专题之函数组合专题系列第十六篇,讲解函数组合,并且使用柯里化和函数组合实现模式需求我们需要写一个函数,输入,返回。 JavaScript 专题之从零实现 jQuery 的 extend JavaScritp 专题系列第七篇,讲解如何从零实现一个 jQuery 的 ext...

    Maxiye 评论0 收藏0
  • lodash源码分析之去重--uniq方法

    摘要:包是开发中常用的工具包,里面有许多实用的方法,今天分析常用的一个去重方法用法源码包可以看到,函数这边只做了一个针对的封装,所以继续看源码 lodash.js包是node开发中常用的js工具包,里面有许多实用的方法,今天分析常用的一个去重方法---uniq 用法 _.uniq([2, 1, 2]) // => [2, 1] 源码包 // uniq.js i...

    Hujiawei 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<