【JS基础】通俗易懂的讲清楚去抖/防抖、节流。外加手写深度比较

2023-11-17

去抖/防抖

去抖也叫防抖,为了照顾JS初学者的理解和记忆,我就简单的说明一下。

我们生活中很多出现抖动的现象,都是没有规律的,例如人的发抖、树叶在风中的抖动、海浪的摆动等。那么去抖,防抖这个概念能够见词答意的看出,就是为了抵消无规律的抖动。怎么个抵消法呢?就是在一段固定的时间内,抖动现象停止了,那么就立即发出信号。

抖动停止发出信号,抖动停止发出信号… 是不是,好像就变成了一种有规律的现象了。

好,我举个应用的例子你就更加明白了,页面上有个搜索框,用户在上面输入关键词,输入完后触发input事件,这时事件的处理逻辑就是发送异步请求去获取关键词的搜索结果。此时,用户只要一输入一个字,立马就会发送请求,当用户连续的输入时,就会连续的发送多个请求,会出现什么问题?

  • 异步请求的相应时间是无法确定的,可能第3个请求的数据量比较大返回的时间久,而最后一个请求数据量小一下子就返回了,那么最后一个请求的数据就会在第3个请求回来之前获取到,而第3个请求的结果最后才获取到,也就是说,最终显示的搜索结果变成了第3个请求的结果。蛋疼不?
  • 连续短时间内无规律的发送多个异步请求,对前端性能非常不友好(页面卡顿),对服务器也不友好(几万个用户同时这么去搜索请求服务器遭不住啊)

这时候就用到了防抖机制,我们在用户停止输入1s后,再去调用异步请求,是不是就大大减少了请求的数量。例如用户连续快速输入“广东省深圳市”,假如没有防抖机制,输入完后一共无规律的发送了6个接口,有了防抖机制,只发送了1次,就是用户输入完"市"停止1s的时候。

代码简单实现:

function debounce(fn, delay = 500) {
  let timer = null;

  return function() {
    if (timer) {
      clearTimeout(timer);
    }

    timer = setTimeout(() => {
      fn(...arguments);
      timer = null;
    }, delay);
  };
}

input1.addEventListener(
  "keyup",
  debounce(function(event) {
    console.log(event.target);
    console.log(input1.value);
  }, 600)
);

下面看为什么这么写

思路解析

首先咱们要设计输入和输出,输入的话我们必定要传入需要防抖的函数本体,然后第二个参数咱们可以设置防抖的时长。输出我们就返回一个包了一层防抖机制的新函数。

function debounce(fn, delay = 500) {
  return function() {
  };
}

防抖机制的设计,只要涉及到了计数咱们只考虑setTimeOut,因为setInterVal当页面卡顿时计数也会受到影响。

function debounce(fn, delay = 500) {
  return function() {
  	let timer = setTimeout(() => {
      fn();
      timer = null;
    }, delay);
  };
}

使用的时候报错了,因为console.log(event.target)中的event为undefined。这是因为咱们的监听事件的默认参数并没有传入到fn里。所以我们要在返回的函数中,传入默认的参数。

function debounce(fn, delay = 500) {
  let timer = null;
  console.log('arguments', arguments) // 这里是debounce的默认参数
  return function() {
    if (timer) {
      clearTimeout(timer);
    }

    timer = setTimeout(() => {
      fn(...arguments); // 这里是return function的默认参数,也就是keyup传进来的,可能一开始会有点难理解
      timer = null;
    }, delay);
  };
}

除了优化【查】的操作,在【增删改】的接口调用时,如果以按钮之类的形式去触发,也一定要考虑到去抖的操作,当然这种情况不一定要使用去抖的写法,用个局部loading也是不错的选择。


节流

节流,节流,节约流水(doge),哈哈,JS初学者完全可以这样子去理解。当我们去开水龙头的时候,水是不是就一直哗啦啦的流出,在一些场景下很浪费水资源,这时我们可以拧紧调节水龙头,让水滴每0.3s滴一滴,是不是就很节约流水啦。

说白了节流是当频繁触发时,保持一定的频率触发。

举例子吧,例如js中的drag、scroll、mousemove事件,就拿mousemove事件说明,当我们移动鼠标想获取实时x、y坐标处理业务逻辑的时候,mousemove事件被浏览器频繁的触发(像流水一样一发不可收拾)会有什么坏处?

  • 大量的x、y数据的处理并不是我们所需要的,多余的处理只会增加浏览器资源开销,这种情况出现多了会有浏览器卡顿的现象。

这时候,就需要保持一定的频率的获取x、y坐标,例如0.5s获取一次。这样能够大大减轻性能负担,又不失去时效性。

function throttle(fn, delay = 100) {
    let timer = null

    return function () {
        if (timer) {
            return
        }
        timer = setTimeout(() => {
            fn.apply(this, arguments) // 把默认的event入参指向要执行的函数
            timer = null
        }, delay)
    }
}

div1.addEventListener('drag', throttle(function (e) {
    console.log(e.offsetX, e.offsetY)
}))

对比防抖可以看出,节流关注的是过程,而防抖关注的是结果。

注意!工作中尽量不要自己造轮子去使用防抖和节流,应该使用成熟的工具库,例如loadsh


两者在vue中结合计算属性使用

个人认为在vue中,把防抖和节流结合计算属性比较好用。

computed: {
	// 防抖的
	debounceBtnClick(){
		return this.debounce(this.btnClick, 300) // btnClick就是method中真正要触发的函数,在模板中的方法里绑定该计算属性即可
	},
	// 节流的未来补充
}

深度比较

就是比较两个变量是不是内容一样的,主要是考虑多层对象或者数组。

// 判断是否是对象或数组
function isObject(obj) {
    return typeof obj === 'object' && obj !== null
}
// 深度比较
function isEqual(obj1, obj2) {
    // 1 如果是值类型的话就直接比较
    if (!isObject(obj1) || !isObject(obj2)) {
        return obj1 === obj2
    }
    // 2 如果传了同一个变量进来直接返回true
    if (obj1 === obj2) {
        return true
    }
    // 3 两个都是对象或数组,而且不相等
    // a 为了性能,可以先比较属性个数或数组大小
    const obj1Keys = Object.keys(obj1)
    const obj2Keys = Object.keys(obj2)
    if (obj1Keys.length !== obj2Keys.length) {
        return false
    }
    // b 以obj1为基准,和obj2递归比较
    for (let key in obj1) {
        const res = isEqual(obj1[key], obj2[key])
        if (!res) { // 不一样的直接返回false
            return false
        }
    }
    // 相等就返回true
    return true
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【JS基础】通俗易懂的讲清楚去抖/防抖、节流。外加手写深度比较 的相关文章

  • Typescript:按值检查对象是否存在于数组中

    我有这个数据 roles roleId 69801 role ADMIN roleId 69806 role SUPER ADMIN roleId 69805 role RB roleId 69804 role PILOTE roleId
  • HTMLImageElement 作为 React Child 无效

    我正在尝试异步加载图像 并且仅在加载图像后才将其显示在 React 应用程序中 componentDidMount const img new Image img onload gt this setState originalImage
  • ant-d upload中如何为removeFile添加PopConfirm一个图片文件

    我正在使用 Ant d Upload 通过本地系统上传文件 然后单击文件预览图像上的删除图标 图像文件将被删除 我想添加一个弹出确认 所以我尝试在 onRemovefunction 中添加确认作为承诺但它不起作用 它在浏览器中显示警报 on
  • 计算Javascript中两次点击之间的时间

    我想用 javascript 计算属性的两次点击之间的时间 但我不知道如何 例如 a href click here a 如果用户单击多次 假设 5 秒内 我想显示警报 如果有帮助的话我正在使用 jQuery 我对 javascript 不
  • 创建 Cookie 时需要帮助

    我有一个名为yes和另一个名叫no
  • 保存/导出Chrome的JavaScript控制台输入历史记录

    无论如何 我可以保存或导出 JavaScript 控制台的历史记录吗 input 控制台历史记录 在 Google Chrome 中 我不想保存输出或错误 因此将鼠标悬停在控制台框上 右键单击并选择Save as 不是解决方案 我不想每次都
  • 如何记录返回的事件发射器

    如何记录所发出的事件stream返回于MyFunc 与 JSDoc MyFunc description param Object opts description return Stream description function My
  • AJAX:检查字符串是否为 JSON?

    我的 JavaScript 有时会在这一行崩溃 var json eval this responseText 当争论时会导致崩溃eval 不是 JSON 在进行此调用之前有什么方法可以检查字符串是否为 JSON 我不想使用框架 有什么方法
  • jQuery 选择器:为什么 $("#id").find("p") 比 $("#id p") 更快

    该页面的作者 http 24ways org 2011 your jquery now with less suck http 24ways org 2011 your jquery now with less suck断言 jQuery
  • 如何将 Browserify 与外部依赖项一起使用?

    我正在尝试慢慢地将 Browserify 引入我的网站 但我不想重写所有 js 也不希望 jquery 和其他库的重复实例与我的 Browserify 版本捆绑在一起 如果我构建将 jquery 列为外部依赖项的模块 那么如何将其指向我的全
  • Keycloak javascript 适配器 `keycloak.init` 加载 404 iframe

    我正在尝试使用 javascript 适配器将 Keycloak 集成到我的客户端应用程序keycloak js 但是 我似乎无法让它发挥作用 这是我的代码 const keycloak new Keycloak realm my real
  • 从多维无穷大数组中删除数组元素

    我想删除一个特定元素 例如 我想删除元素id 76在下面的数组中 而且 数组可以无限地组合在一起 这里的问题是我无法刷新页面 因为我使用 Vue js 进行即时操作 如果我能做到这一点 我的下一个问题可能是如何在我现在想要的地方添加一个元素
  • Jquery:选择菜单以显示和隐藏某些div元素

    我正在创建一个选择菜单 根据所选选项显示和隐藏某些 div 像这样的东西
  • 如何获取使用 .map 渲染的第一个元素的 ref?

    我需要在几行中显示视频 卡片 的缩略图 并重点关注第一个缩略图 我使用嵌套地图进行了显示 该代码基本上迭代视频数组并返回多行视频 我们如何关注第一个渲染的元素 我认为我们需要获得第一个要聚焦的元素的引用 但是我们如何在这里设置 ref 并在
  • 您如何看待引导模式触发器的相应回调?

    On 引导模态 http getbootstrap com javascript modals 我们知道我们可以为触发器绑定事件 例如show or hide using show shown hide hidden 但此事件绑定仅适用于一
  • 在javascript中动态生成行?

    我是 javascript 新手 我想在按下 Tab 时动态生成行 并希望获取在动态生成的行中输入的值 以便我可以在 servlet 代码中使用这些值 这是我的html
  • Restangular - _.contains() 不是一个函数

    如果您最近通过 Bower 更新了 Restangular 它将安装最新的 Lodash 新的 4 0 然而 这是一个问题 因为 Restangular Angular 现在会抛出错误 contains 不是函数 你怎么解决 解决方案非常简
  • 如何在 SVG 元素上使用箭头标记?

    我需要在 d3 js 中创建一个箭头 但我找到的只是带有节点图的示例 我需要的是简单地制作一个从 A 点到 B 点的箭头 我尝试实现以下示例中的部分代码 http bl ocks org 1153292 http bl ocks org 1
  • 如何更改订阅值?使用 rxJS

    我正在创建一个计时器 需要你的帮助 我刚刚学习 Angular 和 rxJS 对此我有一些疑问 我正在创建一个具有启动 停止 暂停 重置功能的计时器 并且 btn Reset 必须将我的计时器 暂停 到 300 毫秒 怎么做 D 我的启动定
  • Bootstrap 3 / 显示模式不适用于 javascript 方式

    我用Modal http getbootstrap com javascript modalsBootstrap 3 0 的功能 我有这个代码 a href myNestedContent Open the modal containing

随机推荐

  • OPENCV C++ 找到最大内接矩形(正方形)

    OPENCV C 找到最大内接矩形 正方形 这源代码本来是检测最大内接圆形的 本人想要矩形 所以变成了正方形 谨慎使用 不是严格意义上的最大内接矩形 cv Mat map one label cv imread src png cv2 IM
  • 程序员,不止干到35岁

    程序员 不止干到35岁 在中国 程序员不能超过35岁 似乎已经是不争的事实 软件开发工作就是青春饭 顶多靠毕业这十年的时间 超过这个年龄 要不成功跃身成为管理者 要不转行进入其他领域 好像再没有更好的选择 即使偶有继续坚持作开发的 也被看成
  • Mybatis简单的增删改查和mybatis配置文件的详解

    MyBatis 1 什么是Mybatis MyBatis是一款优秀的持久层框架 MyBatis避免了几乎所有的JADBC代码和手动设置参数以及获取结果集 MyBatis可以使用简单的XML或注解来配置和映射原生类型 接口和Java的POJO
  • 使用Jest测试接口时间

    引言 在开发和测试过程中 我们经常需要对接口的性能进行评估和优化 一个重要的指标是接口的执行时间 本文将介绍如何使用Jest来测试接口的执行时间 并提供示例代码 Jest简介 Jest 是一个流行的JavaScript测试框架 广泛应用于前
  • 整理了60个 Python 实战例子,拿来即用

    大家好 最近有一些朋友问我有没有一些 Python 实战小案例 今天我整理排版了一遍 给大家分享一下 喜欢记得点赞 收藏 关注 整理了60个Python小例子 拿来即用 一 数字 1 求绝对值 绝对值或复数的模 公众号 快学Python I
  • python与pyqt5把列表中的数据写入到一个新的excel表中,并选择保存路径

    您可以使用 Python 的 openpyxl 库来实现这个功能 首先 您需要通过在命令行中运行 pip install openpyxl 来安装 openpyxl 库 然后 您可以使用以下代码来将列表中的数据写入新的 Excel 表中 f
  • mysql中drop语法错误,mysql 中drop 库的问题

    最近drop database pai 报错 ERROR 1010 HY000 Error dropping database can t rmdir pai errno 39 我就想把库文件直接删除试试 于是 rm rf usr loca
  • 区块链的基本概念

    区块链是分布式数据存储 点对点传输 共识机制 加密算法等计算机技术的新型应用模式 所谓共识机制是区块链系统中实现不同节点之间建立信任 获取权益的数学算法 区块链技术的内涵可概括为 在缺少可信任的中央节点和可信任的通道的情况下 分布在网络中的
  • All O`one Data Structure

    学习地址 双向链表 key为count数 value为存入的字符串 增加一个字符串 先判断其Node位置 再在双向链表中插入 删除也是 最大最小的字符串数在双向链表的表尾和表头 记录学习一下 class AllOne Node root M
  • STM32的介绍及MDK

    文章目录 STM32介绍 单片机 STM32命名 armV7的三个系列 STM32系统结构 CMSIS标准 STM32F4方包绍官方库包 STM32F103 STM32F103资源 STM32F103总线架构 STM32F103引脚 STM
  • 基于keras的图像分类CNN模型的搭建以及可视化(附详细代码)

    基于keras的图像分类CNN模型的搭建以及可视化 本文借助keras实现了热图像的分类模型的搭建 以及可视化的工作 本文主要由以下内容组成 Keras模型介绍 CNN模型搭建 模型可视化 Keras模型介绍 简介 Keras 是 Goog
  • Canvas实例之鼠标移动特效(彩色小球)

    实现鼠标移动跟随着绽放的彩色小球 完整代码在文档末尾 图示 思路 获取画布 获取画布 var canvas document getElementById mycanvas 获取上下文 var ctx canvas getContext 2
  • 嵌入式毕业设计 树莓派实现口罩佩戴检测识别 - 单片机 物联网 机器视觉

    文章目录 0 前言 1 简介 2 主要器件 3 实现效果 4 硬件设计 树莓派4B 5 软件说明 Debian Pi Aarch64 树莓派操作系统 vnc 远程连接树莓派 opencv 摄像头人脸数据采集 人脸数据显示等 6 部分核心代码
  • 顺序表、链表元素的就地逆置。

    目录 一 顺序表元素的就地逆置 1 完整代码 2 解题思路流程 二 链表元素的就地逆置 1 完整代码 2 解题思路流程 一 顺序表元素的就地逆置 1 完整代码 include
  • Vue的生命周期

    一 初始化阶段 1 new Vue Vue实例化 组件也是一个小的Vue实例 2 Init Events Lifecycle 初始化事件和生命周期函数 3 beforeCreate 生命周期钩子函数被执行 4 Init injections
  • 战争科学论——认识和理解战争的科学基础和思维方法

    胡晓峰 1973年中学毕业赴湖南农村插队当过三年知青 1976年回城后当过工人 1977年考入国防科技大学系统工程与数学系信息系统工程专业学习 1981年底毕业后留校任教 后又攻读了研究生 1987年在读信息系统工程研究生期间 曾赴美国加州
  • GDAL-2.4.0 获取Hadoop-3.1.2 hdfs tif文件信息

    GDAL 2 4 0 获取Hadoop 3 1 2 hdfs tif文件信息 GDAL 2 4 0增加了以下功能 Add vsihdfs virtual file system handler for Hadoop File System
  • Android 反编译Apk,修改资源,重新打包,签名发布

    本文简单介绍apk是如何修改logo ic launcher 类似的资源文件修改也可以通过此方式 不过要修改class的话就要涉及到smali的学习了 这里就暂且不谈 后续有需要再做更新 一 工具介绍 apktool 用来反编译apk ap
  • 【华为OD机试真题 JAVA】最多的连续胡杨棵树

    标题 最多的连续胡杨棵树 时间限制 1秒 内存限制 262144K 语言限制 不限 近些年来 我国防沙治沙取得显著成果 某沙漠新种植N棵胡杨 编号1 N 排成一排 一个月后 有M棵胡杨未能成活 现可补种胡杨K棵 请问如何补种 只能补种 不能
  • 【JS基础】通俗易懂的讲清楚去抖/防抖、节流。外加手写深度比较

    文章目录 去抖 防抖 思路解析 节流 两者在vue中结合计算属性使用 深度比较 去抖 防抖 去抖也叫防抖 为了照顾JS初学者的理解和记忆 我就简单的说明一下 我们生活中很多出现抖动的现象 都是没有规律的 例如人的发抖 树叶在风中的抖动 海浪