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

前言

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

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 都是执行的同一个函数。

后续

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

相关推荐
y先森12 分钟前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy12 分钟前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu108301891115 分钟前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿1 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡2 小时前
commitlint校验git提交信息
前端
虾球xz3 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇3 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒3 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员3 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐3 小时前
前端图像处理(一)
前端