优化用户体验:防抖节流技术的魔力(一)

前言

我们在处理频繁触发事件时,JavaScript的防抖技术能够帮助开发者优化页面性能和提升用户体验。本文将重点介绍如何使用JavaScript实现防抖功能,让我们一起深入探讨JavaScript在优化Web应用中的重要作用吧!"

正文

在JavaScript中,防抖(Debouncing)是一种常用的技术,用于处理频繁触发的事件或函数调用。防抖的主要目的是确保在连续触发事件时只执行一次相应的处理函数,以减少性能开销和提升用户体验。

当某个事件被频繁触发时,如果没有使用防抖,每次事件触发都会导致相应的处理函数被执行。这可能会造成性能问题,尤其是在一些需要频繁触发事件的场景下,比如输入框输入事件、窗口大小变化事件等。

通过使用防抖技术,我们可以设置一个等待时间间隔,在该时间间隔内如果事件再次触发,则重新计时。只有当事件停止触发一段时间后,才会执行相应的处理函数。这样可以有效减少函数执行的次数,提升页面性能和响应速度。

我们先看看一段代码:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="btn">提交</button>

  <script>
    let btn = document.getElementById('btn')
    btn.addEventListener('click', function(){
        console.log('提交');
    })
 </script>
</body>
</html>

在这段代码中,按钮(btn)的点击事件(click)绑定了一个事件处理函数,当用户点击按钮时会在控制台打印出"提交"。如果没有设置防抖,可能会出现以下问题:

  1. 多次触发事件:如果用户手抖的话快速点击按钮多次,每次点击都会触发事件处理函数,导致"提交"被打印多次在控制台上。这可能会造成不必要的重复操作或影响用户体验。
  2. 性能问题:频繁触发事件处理函数可能会导致页面性能问题,特别是在处理复杂逻辑或操作时。过多的事件处理可能会导致页面变得卡顿或响应变慢。
  3. 数据处理问题:如果事件处理函数涉及到数据请求或操作,频繁触发事件可能会导致数据处理混乱或出现错误,影响页面的功能正常运行。

因此,为了解决这些问题,可以使用防抖技术来控制事件处理函数的执行频率,避免不必要的重复执行,提升页面性能和用户体验。那我们要怎么才能解决这些问题呢,接下来我们就要来剖析防抖的源码了。

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="btn">提交</button>

  <script>
    let btn = document.getElementById('btn')
    function send(e) {
      console.log(this, '提交完成', e);
    }

    btn.addEventListener('click', debounce(send, 1000))


    function debounce(fn, delay) {
      let timer;

      return function() {
        let args = arguments

        if (timer) clearTimeout(timer)

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

    }
 
 </script>
</body>
</html>

这段代码就是在前面那段没有使用防抖的代码的基础上加上了防抖。这段代码里有两个小知识点:

  1. arguments:

    • arguments 是一个类数组对象,它包含了函数被调用时传入的所有参数。即使函数没有明确定义参数,也可以通过 arguments 对象来访问传入的参数。

    • arguments 对象在函数内部始终是可用的,可以用于获取所有传入的参数,无需提前声明函数参数。

    • 例如,在下面的函数中,arguments 可以用来获取所有传入的参数:

      javascript 复制代码
      function example() {
        console.log(arguments); // 输出传入的所有参数
      }
      example('a', 'b', 'c');
  2. ...args 解构:

    • ...args 是展开语法(spread syntax),用于将一个数组或类数组对象展开成独立的参数序列。

    • 当使用 ...args 时,它会将数组中的每个元素作为独立的参数传递给函数。

    • 例如,在下面的示例中,...args 会将数组中的元素作为独立的参数传递给函数:

      scss 复制代码
      function example(a, b, c) {
        console.log(a, b, c);
      }
      let arr = [1, 2, 3];
      example(...arr); // 等同于 example(1, 2, 3);

接下来我们来分析这段代码

  • 步骤1 :在使用防抖的代码中,我们定义了一个名为 debounce 的函数,用于实现防抖功能。该函数接受两个参数:原始的事件处理函数 fn 和延迟时间 delay。
  • 步骤2 :在 debounce 函数内部,我们声明了一个变量 timer 用于记录定时器。然后返回一个新的函数,该函数会在延迟时间内执行原始的事件处理函数。
  • 步骤3 :在返回的函数中,我们使用闭包来保存原始事件处理函数 fn 和延迟时间 delay。当该函数被触发时,会先保存传入的参数 arguments,然后判断是否存在之前的定时器,如果存在则清除之前的定时器。
  • 步骤4 :接着,我们设置一个新的定时器,在延迟时间 delay 后执行原始的事件处理函数 fn。在执行时,使用 call 方法确保事件处理函数在正确的上下文中执行,并将之前保存的参数传递给事件处理函数。

通过以上步骤,我们成功实现了一个简单的防抖函数,在按钮点击事件上应用了防抖功能,避免了频繁点击按钮可能带来的性能问题。

总结

总结一下吧,编写防抖函数的思路如下:

  1. 定义防抖函数 :首先需要定义一个函数,例如 debounce,该函数接受两个参数:原始的事件处理函数 fn 和延迟时间 delay。
  2. 返回一个新的函数 :在 debounce 函数内部,返回一个新的函数,这个新函数会在延迟时间内执行原始的事件处理函数。
  3. 使用闭包保存状态 :在返回的新函数中,使用闭包来保存原始事件处理函数 fn 和延迟时间 delay,以便在定时器触发时能够访问这些值。
  4. 触发时清除定时器:在新函数内部,每次触发时先清除之前的定时器,以确保只有最后一次触发会执行事件处理函数。
  5. 设置新的定时器 :在清除定时器后,设置一个新的定时器,在延迟时间 delay 后执行原始的事件处理函数。在执行时,使用 call 方法确保事件处理函数在正确的上下文中执行,并传递之前保存的参数。

若是闭包方面有不懂的可以看看作者前面写的文章。本篇文章和下一篇文章关于节流的文章一起食用更佳。

相关推荐
10年前端老司机17 分钟前
Next.js+LangGraph.js+ 简历工具AI Agent完整落地
前端·langchain·agent
IT_陈寒5 小时前
Java中equals方法比了个寂寞?原来这才是正确的重写姿势
前端·人工智能·后端
默_笙5 小时前
🚓 分诊台与拆题术:让 RAG 学会判断和规划
前端·javascript
CopyCode5 小时前
用 AI 迁项目有多爽?我把 Webpack 迁 Vite 的全过程记下来了
前端·架构
去伪存真5 小时前
Electron 自动化发布指南:GitHub Actions 跨平台打包全纪录
前端·electron
计算机魔术师5 小时前
OpenAI智能体失控闯进美国政府网站,53张用户图片外泄背后
前端
颜进强5 小时前
14 · NestJS ExecutionContext 执行上下文:守卫、拦截器、过滤器拿到的"同一个 context",为什么能力不一样?
前端·后端·ai编程
程序员Flycan5 小时前
🚀 跨域终结者:前端代理服务器(Proxy)原理解析与配置总结
前端
怕浪猫5 小时前
顶级模型一句话,AI 写出了能玩的 QQ飞车
前端·面试·github
huakoh5 小时前
MCP 报错分不清?先看响应里是 result 还是 error
前端