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

前言

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

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

后续

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

相关推荐
rexling124 分钟前
【Spring Boot】Spring Boot解决循环依赖
java·前端·spring boot
我有一棵树26 分钟前
Vue 项目中全局样式的正确写法:不要把字体和主题写在 #app 上
前端·javascript·vue.js
Luna-player1 小时前
npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本,解决方法
前端·npm·node.js
悢七1 小时前
windows npm打包无问题,但linux npm打包后部分样式缺失
linux·前端·npm
Felicity_Gao1 小时前
uni-app App升级功能实现
前端·学习·uni-app
CS Beginner2 小时前
【搭建】个人博客网站的搭建
java·前端·学习·servlet·log4j·mybatis
老程序员刘飞3 小时前
node.js 和npm 搭建项目基本流程
前端·npm·node.js
歪歪1003 小时前
在C#中除了按属性排序,集合可视化器还有哪些辅助筛选的方法?
开发语言·前端·ide·c#·visual studio
wangbing11253 小时前
开发指南139-VUE里的高级糖块
前端·javascript·vue.js
半桶水专家4 小时前
Vue 3 动态组件详解
前端·javascript·vue.js