栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > JavaScript

JS专题之去抖函数

JavaScript 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JS专题之去抖函数

一、前言

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

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

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

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

二、简单版去抖(debounce)

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

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

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

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

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

输入框:

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

  1. debounce 函数在主线程顺序执行时已经被调用,传入的参数一个是真正想在事件触发执行的事件处理函数
  2. 另一个参数是事件触发的间隔时间,间隔时间内再次触发事件,则重新计时,类似于罚你 5 分钟内不准说话,时间到后就可以开始说话,如果 5 分钟内说话了,则再罚你 5 分钟内不准说话,以此类推~
  3. debounce 函数有一个 timer 内部变量,timer 在返回的执行函数中被访问,形成了闭包,有关闭包的内容,可以翻看我之前的文章《Javascript之闭包》
  4. bebounce 函数返回的匿名函数才是 input 事件的回调函数,所以该匿名函数有一个默认参数 event 对象。
  5. 同第 4 点,匿名函数是 dom 元素注册事件的回调函数,所以匿名函数(回调函数)的 this 指向 HTMLInput 元素。
  6. 同第 2 点,触发函数后,如果发现闭包中保存着 timer 变量, timer 变量初始值为 null, 之后触发定时器后,timer 为当次定时器的 id,id 是一个数字。去抖的过程在于,如果在定时器的间隔时间内触发了函数,它会把上一次事件触发时定义的定时器清除,又重新定义一个定时器。如果本次定时器没有被清除,时间到后就会自然执行事件处理函数。对这个过程有困惑的同学,可以把 timer 变量在 clearTimeout 之前打印出来就明白了。
  7. 延时执行了事件处理函数(handler),需要传递调用对象和事件对象过去,此处 call 可以和 apply 互换,如果用 apply, 传递 arguments 类数组即可。这样保证了参数的一致性,就像没被 debounce 处理过一样。

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

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

三、立即执行

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

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

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

取消功能实现

输入框:

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

  1. 非立即执行版本和前一节内容一样,跳过。
  2. timer 初始值为 null, 第一次触发为立即执行,!timer 为 true, 所以能够立即调用事件处理函数。
  3. 每次事件触发, 都会把 timer 重新赋值,在间隔时间到之前 timer 为数字 id, !timer 为 false, 所以不能立即执行。如果间隔时间到了,会把当次事件触发的定时器 id 置为 null, 下一次事件触发就能立即执行了。
  4. 朋友们可以通过观察 timer 值的变化,思考整个过程,timer 在去抖的过程中充当 flag 的作用,可以用来判断能否立即执行。

看看效果:

取消函数

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

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

输入框:

看看效果:

总结

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

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

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号