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

前言

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

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

后续

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

相关推荐
全栈测试笔记14 分钟前
异步函数与异步生成器
linux·服务器·前端·数据库·python
EndingCoder31 分钟前
配置 tsconfig.json:高级选项
linux·前端·ubuntu·typescript·json
木风小助理37 分钟前
JavaStreamAPI的性能审视,优雅语法背后的隐形成本与优化实践
java·前端·数据库
white-persist2 小时前
轻松抓包微信小程序:Proxifier+Burp Suite教程
前端·网络·安全·网络安全·微信小程序·小程序·notepad++
敲敲了个代码3 小时前
多标签页强提醒不重复打扰:从“弹框轰炸”到“共享待处理队列”的实战
java·前端·javascript·面试·架构
不想上班只想要钱3 小时前
动态类名在 <swiper-slide 的复制项中没有起作用的解决方法
前端·vue.js
weixin_395448913 小时前
tidl_import_mul_rmfsd_psd_u8_3x480x544_bise_raw_dynamic.txt
java·服务器·前端
Jinuss4 小时前
源码分析之React中updateContainerImpl方法更新容器
前端·react.js·前端框架
Mr Xu_4 小时前
Vue + Element Plus 实现前端导出 Excel 功能详解
前端·javascript·vue.js
仰泳之鹅5 小时前
【杂谈】使用Edge浏览器下载文件显示“Microsoft Defender SmartScreen 已阻止此不安全文件”的解决方法
前端·edge