面试官叫我手写一个防抖,稳啦!


theme: lilsnake

前言

在JavaScript的舞台上,函数就像是那些喜欢搞怪的小丑,总是在你不经意间跳出来捣乱。你一不留神,它们就像是集体疯狂了似的,同时争先恐后地执行,把你的页面搞得乱七八糟。这时候,就需要一个“大魔术师”来驯服它们了——这就是JavaScript中的防抖!

想象一下你是一位驯兽师,而JavaScript函数就像是你的驯兽场里的各种动物,其中有些像是永远停不下来的兔子,有些则像是无法控制的疯狂狮子。而防抖就是你的秘密武器,它让你能够控制这些顽皮的“动物们”,不再让它们在你的舞台上胡闹,而是乖乖地按照你的指令表演。

或者,你可以把JavaScript函数想象成一群喜欢“开派对”的好友,他们总是在你不经意间组织聚会,搞得你焦头烂额。而防抖就像是给了你一个魔法的遥控器,只要一按下去,这些好友们就会暂时安静下来,不再频繁地来打扰你,让你有时间去做其他的事情。

又或者,你可以把JavaScript函数比喻成一群“暴躁的厨师”,他们总是在厨房里乱做一团,把你的代码搞得一团糟。而防抖就像是给了你一根魔法的鞭子,只要你挥舞一下,这些“厨师们”就会老老实实地排队等候,不再一窝蜂地冲进厨房,让你的代码变得井井有条。

无论你用怎样幽默的比喻,防抖都是JavaScript中一个非常实用的技巧,能够让你的代码更加优雅、高效。它就像是给了你一把“大魔术师”的魔杖,让你能够驯服那些调皮捣蛋的函数,让它们在你的指挥下乖乖地表演,不再像一群闹哄哄的小丑一样惹人头疼。所以,当你的JavaScript函数们再次想要在舞台上频频出现时,记得拿出你的“大魔术师”魔杖,让它们安静下来,听从你的指挥吧!

1.话题引入


  
  
  Document

提交

当我们设置一个提交按钮,当我们不断点击提交的时候,也会导致多次提交,那么能不能有一种机制,让我不断提交多次,只执行最后一次呢?这便是防抖的机制。单位时间内提交多次事件,只执行最后一次。

2.防抖初级


  
  
  Document

提交

我们这段代码是防抖的初级写法,能让我们意识到防抖的本质。首先我们要知道提交事件后面必须跟一个不调用的函数,但是我们的防抖函数必须传参,那么我们可以在防抖函数里面返回一个函数体,这样在执行事件提交前我们仍然没有执行防抖函数里面返回的函数。

  1. 这段代码和我们就是我们之前所学到的闭包,执行事件提交前,按理来说防抖函数执行完毕,里面所有的东西都应该被回收掉,但是我们返回的函数里有用到防抖函数里面的timer,因此会留下它。
  2. 接下来当我们触发事件时,返回函数就将执行,先清除上一个定时器,然后1秒后执行handle函数,如果在1秒内又再次触发,那么上一个将不会执行,直到在一次触发后一秒都不会触发,才会打印执行结果。这就是防抖函数的机制。单位时间内提交多次事件,只执行最后一次。

3.防抖高级


  
  
  Document

提交

初级防抖打印handle里的this和e

高级防抖打印handle里的this和e 我们需要知道两点,在我们将handle作为参数传给防抖函数时,出现了两个问题。

  1. handle本身this作为事件里参数要指向btn,结果指向了全局。
  2. handle里的e丢失了。

针对于第一种情况,我们要知道,最终的handle是被定时函数调用了,而定时函数的回调函数中this指向全局,那么我们就将handle函数放入箭头函数内,箭头函数内不含this,因此this在定时函数内做参数,而这时候的this就在返回函数内而处于定时函数外,因为是作为参数传进来的。那么这个时候this顺利指向了btn。

针对第二种情况,我们知道handle函数丧失了e是因为这个时候handle函数不再作为提交事件直接调用的函数,这个时候的e存在于返回函数中,因此我们只需要将返回函数里的e传给handle就可以了。

这样我们就完成了完整的一个防抖函数,稳啦!

4.小结

JavaScript中的防抖(Debouncing)是一种常用的优化技术,用于控制函数在连续触发时的执行频率,确保函数在指定的时间间隔内只执行一次。其应用场景和实现思路如下:

应用场景:

  1. 输入框搜索:当用户在输入框中输入搜索关键字时,可以利用防抖技术延迟搜索请求的发送,等待用户停止输入一段时间后再进行搜索,从而减少不必要的网络请求和服务器负载。
  2. 窗口调整:当窗口大小调整时,会触发resize事件,使用防抖可以延迟执行窗口调整相关的操作,确保在用户完成调整后才进行相应的处理,提高性能和流畅度。
  3. 按钮点击:防止用户在短时间内多次点击按钮导致重复操作,可以使用防抖确保按钮点击事件只执行一次,避免不必要的多次请求或操作。

实现思路:

  1. 利用定时器:在事件处理函数中设置一个定时器,在触发事件时先清除之前的定时器,然后重新设置一个新的定时器。如果在指定的时间间隔内再次触发事件,则会重新计时,直到事件停止触发,定时器超时后才执行函数。
  2. 函数闭包:通过闭包保存定时器的标识,确保在函数多次触发时能够正确清除和设置定时器,实现防抖效果。
  3. 事件监听器封装:封装一个通用的防抖函数,接收待执行的函数和延迟时间作为参数,在内部实现定时器逻辑,并返回一个新的函数作为事件监听器,用于替代原始的事件处理函数。
  4. 立即执行:根据需求,可以选择是否在触发事件时立即执行函数,还是在事件停止触发后执行函数。

通过以上实现思路,我们可以在JavaScript中方便地应用防抖技术,提高代码性能和用户体验,当看完这篇文章之后,如果面试官让我们手写的话,我们一定会想:稳啦!


这是一个从 https://juejin.cn/post/7368662916152197159 下的原始话题分离的讨论话题