都在讲怎么写防抖,那么你知道怎么用防抖函数的吗

前言

说到防抖,相信做前端的没有谁不知道,甚至说到手写一个防抖函数,也基本是信手拈来。

js 复制代码
function debounce(fn, delay) {
  let timer;
  return function (...args) {
    if (timer) {
      clearTimeout(timer);
    }

    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

使用场景

说到防抖,那还得提一嘴它的使用场景:

  1. 输入框监听用户输入,发送接口请求数据,是没必要没输入一个字符就请求一次的;
  2. 在处理窗口的 resize 事件时,也没必要没监听到变化就触发事件执行;

以上是经典的使用场景,当然,在我们需要限制触发的次数时,都可以考虑使用防抖函数。

遇到的问题

在我自己以前使用防抖的场景中,也基本是上述的两个场景。直接 addEventListener('resize', debounce(fn, 300)),一切都用的理所当然。

然而在最近修改一个问题时,确遇到了点麻烦。

我们系统接入了 qiankun 微前端框架,在频繁切换菜单的时候,会出现几个菜单疯狂的来回跳转,此时只有刷新页面或者等页面崩溃再刷新操作。

在解决这问题的时候,最开始也是准备从 qiankun 这个框架入手,想着是不是因为切换太频繁,导致子应用没有卸载成功,出现了与主应用抢占 URL 的现象。但是经历了各种尝试,发现子应用是卸载成功了的,也没定位到到底是哪儿一直在触发切换URL,或许这得去仔细研究下 qiankun 的源码才能知道了,因为不切换子应用菜单时,是没问题的。但是这个问题又比较紧急,给不了时间去研究,那只能看能不能另辟蹊径了。于是,防抖函数进入了我的脑海。

因为正常情况下,是没有用户会快速频繁切换多个菜单的(排除"找茬"的测试),或者也会有用户这样操作,但我相信这只是会极个别的。因此,在切换菜单时,增加一个防抖处理,是不是也能解决这个问题呢?

于是,我开始在菜单切换的地方开始加入防抖。一开始,我的代码是这样的:

html 复制代码
... (click)="changeTab($event)"
js 复制代码
function changeTab($event) {
  debounce(jump, 100);
}

function jumpTab(tabId) {
  xxx;
}

刚写完,发现不对啊,那个 jumpTab 是需要参数的,但是 changeTab 中没有传参数,jumpTab 是不知道跳到哪个菜单的。于是,我想当然的进行了修改:

js 复制代码
function changeTab($event) {
  debounce(jump($event), 100);
}

改完一执行,发现菜单是可以跳转的,但是那个防抖没用上,在快速切换后,菜单会沿着点击的顺序挨个跳转,还是不行。为啥会不行呢,我去 debounce 函数中打断点一看,每次执行 changeTab 事件时,都在重新执行一遍 debounce,而且这个地方传入的是 jump($event),本身就会执行一次,相当于是这个 debounce 根本就没用。

然后也试过这样写:

js 复制代码
function changeTab($event) {
  debounce(jump, 100)($event);
}

最后结果同上,并没有实现防抖功效。

原本以为自己对防抖函数也算是理解了,但没想到这换个地方用,就不对了。然后又看了一遍 debounce 函数的实现,它是利用了闭包的特质,debounce 返回一个函数,后续的调用实际上都是调用的返回的这个函数,而不是我这种每次都在重新调用 debounce 函数。

那么思路就有了,再定义一个函数,将 debounce 函数执行并返回,在 changeTab 中执行这个新定义的函数。

js 复制代码
function debounceFn = () => debounce(jump, 100)
function changeTab($event) {
  debounceFn($event);
}

这样就能保证每次 changeTab 都是执行的同一个函数。

后续

当然这个问题的解决方法也算是一种取巧,还是得看下为啥会出现这个问题的根因。另一方面,通过这个问题,也加深了自己对防抖函数的认知。

相关推荐
释怀不想释怀1 小时前
Ajax,vue生命周期(自动加载页面发出请求)Axios
前端·javascript·ajax
一点晖光1 小时前
ios底部按钮被挡住
前端·ios·微信小程序
Light608 小时前
CSS逻辑革命:原生if()函数如何重塑我们的样式编写思维
前端·css·响应式设计·组件化开发·css if函数·声明式ui·现代css
蜡笔小嘟8 小时前
宝塔安装dify,更新最新版本--代码版
前端·ai编程·dify
ModyQyW9 小时前
HBuilderX 4.87 无法正常读取 macOS 环境配置的解决方案
前端·uni-app
bitbitDown9 小时前
我的2025年终总结
前端
五颜六色的黑9 小时前
vue3+elementPlus实现循环列表内容超出时展开收起功能
前端·javascript·vue.js
wscats10 小时前
Markdown 编辑器技术调研
前端·人工智能·markdown
EnoYao10 小时前
Markdown 编辑器技术调研
前端·javascript·人工智能
JIngJaneIL10 小时前
基于java+ vue医院管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot