JS 中请求队列与锁的巧妙结合

news2025/2/28 23:20:17

一、引言

在 JavaScript 开发中,尤其是在涉及到异步操作和对共享资源的并发访问时,有效地控制请求顺序和资源访问权限至关重要。例如,在多个网络请求同时针对一个有限制访问频率的 API 或者多个异步任务竞争同一个文件写入权限的场景下,若不加以妥善处理,可能会导致数据混乱、请求失败或资源冲突等问题。本文将深入探讨如何在 JavaScript 中创建一个请求队列,当锁被占用时,将请求妥善地放入队列中,待锁释放后,再依次处理队列中的请求,从而确保系统的稳定性和正确性。

二、JS 中的异步锁实现

(一)简易异步锁对象

  • 构造函数
    • 首先,创建一个名为AsyncLock的函数构造器,用于生成异步锁对象实例。在构造函数内部,初始化以下几个重要属性:
      • this.queue:这是一个数组,用于存储被阻塞的请求任务。初始时,它被设置为空数组,因为还没有任何请求被阻塞。
      • this.isLocked:这是一个布尔值,用于表示锁的当前状态。初始化为false,意味着锁是空闲的,资源可供使用。
      • this.version:这是一个字符串类型的属性,用于记录锁的版本信息。初始版本设置为'0',每当锁状态发生改变(如被获取或释放)时,版本号可以相应更新,这有助于在复杂的应用场景中跟踪锁的使用历史和状态变化。
    • 以下是构造函数的代码示例:
function AsyncLock() {
  this.queue = [];
  this.isLocked = false;
  this.version = '0';
}
  • 获取锁方法 - lock
    • 该方法用于尝试获取锁。如果当前锁已经被其他任务占用(即this.isLocked === true),则需要将当前请求任务加入到等待队列this.queue中。
    • 为了实现等待队列的功能,使用await new Promise(resolve => this.queue.push(resolve));。这里创建了一个新的Promise,并将其resolve函数添加到队列中。当锁被释放时,会从队列中取出这个resolve函数并执行,从而继续执行被阻塞的任务。
    • 如果等待队列的长度已经达到了某个设定的上限(例如 10),则表示系统可能存在资源紧张或者请求过多的情况,此时直接返回false,表示获取锁失败,避免队列无限增长导致内存溢出等问题。
    • 如果成功获取锁(即锁原本是空闲的),则将this.isLocked设置为true,并生成一个新的锁版本号(可以使用Date.now().toString()等方式生成一个基于时间戳的唯一字符串作为版本号)。同时,为了防止锁被无限期占用,设置一个超时机制。如果在获取锁时没有传入特定的超时时间参数,则默认在 300 毫秒后自动释放锁。可以使用setTimeout函数来实现超时释放锁的功能,在超时回调函数中调用this.unlock()方法释放锁。
    • 以下是lock方法的完整代码示例:
AsyncLock.prototype.lock = async function (timeout = 300) {
  if (this.isLocked) {
    if (this.queue.length < 10) {
      await new Promise(resolve => this.queue.push(resolve));
    } else {
      return false;
    }
  }
  this.isLocked = true;
  this.version = Date.now().toString();
  const timer = setTimeout(() => {
    this.unlock();
  }, timeout);
  return true;
};
  • 释放锁方法 - unlock
    • 该方法用于释放当前持有的锁。如果等待队列this.queue中有等待的任务(即this.queue.length > 0),则从队列中取出第一个任务的resolve函数并执行,这将唤醒被阻塞的任务,使其继续执行后续操作。通过const resolve = this.queue.shift(); resolve();实现从队列头部取出并执行resolve函数。
    • 如果等待队列为空,说明没有任务在等待锁,此时将this.isLocked设置为false,表示锁已经被释放,可以被其他任务获取。
    • 以下是unlock方法的代码示例:
AsyncLock.prototype.unlock = function () {
  if (this.queue.length > 0) {
    const resolve = this.queue.shift();
    resolve();
  } else {
    this.isLocked = false;
  }
};
  • 包装锁的获取与释放方法 - withLock
    • 为了更方便地在外部使用锁机制,创建一个withLock方法。这个方法是一个async函数,它内部首先调用this.lock方法尝试获取锁。如果获取锁成功(返回true),则执行传入的任务函数(假设为task),并在任务完成后调用this.unlock方法释放锁。如果获取锁失败(返回false),则直接返回一个表示locked状态的对象或值,以便外部代码进行相应的处理。
    • 以下是withLock方法的代码示例:
AsyncLock.prototype.withLock = async function (task) {
  const locked = await this.lock();
  if (locked) {
    try {
      return await task();
    } finally {
      this.unlock();
    }
  } else {
    return { locked: true };
  }
};

三、使用示例

1、创建AsyncLock的实例:
const asyncLock = new AsyncLock();
2、 定义一个异步函数test来模拟请求任务:
async function test() {
  const result = await asyncLock.withLock(async () => {
    console.log('执行任务');
    // 这里可以添加具体的任务逻辑,例如网络请求、文件操作等
    return '任务完成';
  });
  if (result.locked) {
    console.log('获取锁失败');
  } else {
    console.log(result);
  }
}
3、 多次调用test函数来测试锁机制:
test();
test();
test();

在上述示例中,当第一个test函数调用时,如果锁空闲,它将获取锁并执行任务,打印 “执行任务”,然后释放锁。当第二个和第三个test函数调用时,如果第一个test函数还未释放锁,它们将被加入等待队列。一旦锁被释放,等待队列中的任务将依次被执行,从而实现了请求队列与锁机制的协同工作。

四、总结

在 JavaScript 中,通过精心设计和实现请求队列与异步锁的结合,可以有效地应对并发访问共享资源时可能出现的各种问题。这种机制不仅能够确保资源在同一时间只有一个任务能够访问,避免了数据竞争和冲突,而且通过合理的等待队列管理,能够有条不紊地处理多个请求,提高了系统的整体稳定性和可靠性。在实际的大型 JavaScript 应用开发中,尤其是涉及到复杂的异步操作和资源管理场景时,深入理解和熟练运用这种请求队列与锁的技术是非常必要的,可以帮助我们构建出更加健壮和高效的应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2259681.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MYSQL索引的分类和创建

目录 1、聚簇索引和非聚簇索引 tips&#xff1a; 小问题&#xff1a;主键为什么建议使用自增id? 2、普通索引 &#xff08;常规索引&#xff09;(normal) 3、唯一索引&#xff08;UNIQUE &#xff09; 唯一索引和主键的区别&#xff1a; 唯一约束和唯一索引的区别&#…

Oracle最佳实践-优化硬解析

前段时间参加oracle CAB&#xff0c;oracle高级服务部门做了一个数据库最佳实践的报告&#xff0c;其中就有一项就是解决未使用绑定变量但执行次数很多的SQL&#xff1b; 对于一个数据库来说如果不知道该如何优化&#xff0c;那么最简单最有效的优化就是减少硬解析&#xff0c;…

AI Agent:重塑业务流程自动化的未来力量(2/30)

《AI Agent&#xff1a;重塑业务流程自动化的未来力量》 摘要&#xff1a;整体思路是先介绍 AI Agent 的基本情况&#xff0c;再深入阐述其实现业务流程自动化的方法和在不同领域的应用&#xff0c;接着分析其价值和面临的挑战&#xff0c;最后得出结论&#xff0c;为读者全面…

哈默纳科Harmonic谐波减速机机器人精准高效动力传递的核心力量

在当今科技飞速发展的时代&#xff0c;机器人技术正以惊人的速度改变着我们的生产与生活方式。而在机器人的精密机械结构中&#xff0c;哈默纳科 Harmonic 谐波减速机扮演着不可或缺的角色&#xff0c;成为机器人精准高效动力传递的关键所在。 1.高精度与灵活性&#xff1a;哈默…

【开源项目】经典开源项目数字孪生体育馆—开源工程及源码

飞渡科技数字孪生体育馆管理平台&#xff0c;融合物联网IOT、BIM数据模型、三维GIS等技术&#xff0c;实现体育馆的全方位监控和实时全局掌握&#xff0c;同时&#xff0c;通过集成设备设施管理、人员管理等子系统&#xff0c;减少信息孤岛&#xff0c;让场馆“可视、可控、可管…

长短期记忆神经网络(LSTM)介绍

1、应用现状 长短期记忆神经网络&#xff08;LSTM&#xff09;是一种特殊的循环神经网络(RNN)。原始的RNN在训练中&#xff0c;随着训练时间的加长以及网络层数的增多&#xff0c;很容易出现梯度爆炸或者梯度消失的问题&#xff0c;导致无法处理较长序列数据&#xff0c;从而无…

SQL server学习03-创建和管理数据表

目录 一&#xff0c;SQL server的数据类型 1&#xff0c;基本数据类型 2&#xff0c;自定义数据类型 二&#xff0c;使用T-SQL创建表 1&#xff0c;数据完整性的分类 2&#xff0c;约束的类型 3&#xff0c;创建表时创建约束 4&#xff0c;任务 5&#xff0c;由任务编写…

正则表达式——参考视频B站《奇乐编程学院》

智能指针 一、背景&#x1f388;1.1. 模式匹配&#x1f388;1.2. 文本替换&#x1f388;1.3. 数据验证&#x1f388;1.4. 信息提取&#x1f388;1.5. 拆分字符串&#x1f388;1.6. 高级搜索功能 二、原料2.1 参考视频2.2 验证网址 三、用法3.1 限定符3.1.1 ?3.1.2 *3.1.3 3.1.…

Elasticsearch 集群部署

Elasticsearch 是一个分布式的搜索和分析引擎&#xff0c;广泛应用于日志分析、全文搜索、实时数据分析等场景。它以其高性能、高可用性和易用性而著称。本文档将引导您完成一个基本的 Elasticsearch 集群配置&#xff0c;包括节点间的通信、客户端访问、安全设置等关键步骤。我…

#思科模拟器通过服务配置保障无线网络安全Radius

演示拓扑图&#xff1a; 搭建拓扑时要注意&#xff1a; 只能连接它的Ethernet接口&#xff0c;不然会不通 MAC地址绑定 要求 &#xff1a;通过配置MAC地址过滤禁止非内部员工连接WiFi 打开无线路由器GUI界面&#xff0c;点开下图页面&#xff0c;配置路由器无线网络MAC地址过…

webstorm开发uniapp(从安装到项目运行)

1、下载uniapp插件 下载连接&#xff1a;Uniapp Tool - IntelliJ IDEs Plugin | Marketplace &#xff08;结合自己的webstorm版本下载&#xff0c;不然解析不了&#xff09; 将下载到的zip文件防在webstorm安装路径下&#xff0c;本文的地址为&#xff1a; 2、安装uniapp插…

mHand Pro动捕数据手套在人形机器人领域的具体运用

mHandPro是一款高精度的动作捕捉数据手套&#xff0c;可应用于动作捕捉与VR交互等领域&#xff0c;配套”mHand Studio“引擎&#xff0c;可实时捕捉真人手部位姿及运动轨迹数据&#xff0c;将数据导出还可以用于人形机器人的训练加速高精度机器人操作技能的培训进程。 高精度动…

CNCF云原生生态版图-分类指南(三)- 运行时

CNCF云原生生态版图-分类指南&#xff08;三&#xff09;- 运行时 CNCF云原生生态版图-分类指南三、运行时&#xff08;Runtime&#xff09;&#xff08;一&#xff09;云原生存储&#xff08;Cloud Native Storage&#xff09;1. 是什么&#xff1f;2. 解决什么问题&#xff1…

算法论文/半监督1——2024最新半监督目标检测综述(CNN和Transformer)全文1.5W字

Semi-Supervised Object Detection: A Survey on Progress from CNN to Transformer 摘要 半监督学习的惊人进步促使研究人员探索其在计算机视觉领域内目标检测任务中的潜力。半监督对象检测 &#xff08;SSOD&#xff09; 利用小型标记数据集和较大的未标记数据集的组合。这…

LLMC:大语言模型压缩工具的开发实践

关注&#xff1a;青稞AI&#xff0c;学习最新AI技术 青稞Talk主页&#xff1a;qingkelab.github.io/talks 大模型的进步&#xff0c;正推动我们向通用人工智能迈进&#xff0c;然而庞大的计算和显存需求限制了其广泛应用。模型量化作为一种压缩技术&#xff0c;虽然可以用来加速…

【Linux】常用Linux命令大全(持续更新)

前言 汇总常用linux命令及用法&#xff0c;方便大家在日常工作中操作linux的便捷性 一、top命令 top 是一个在 Linux 系统上常用的实时系统监控工具。它提供了一个动态的、交互式的实时视图&#xff0c;显示系统的整体性能信息以及正在运行的进程的相关信息    在键入top命令…

VLC还是SmartPlayer?Windows平台RTSP播放器低延迟探讨

技术背景 好多开发者在用过大牛直播SDK的RTSP播放器后&#xff0c;都希望我们也分享下&#xff0c;如何在Windows平台实现低延迟的RTSP播放&#xff1f;低延迟的RTSP播放器&#xff0c;说起来容易做起来难&#xff0c;下面&#xff0c;我们从以下维度做个探讨&#xff1a; 播…

28. Three.js案例-创建圆角矩形并进行拉伸

28. Three.js案例-创建圆角矩形并进行拉伸 实现效果 知识点 WebGLRenderer (WebGL渲染器) WebGLRenderer 是 Three.js 中用于渲染 3D 场景的主要渲染器。 构造器 WebGLRenderer( parameters : Object ) 参数类型描述parametersObject渲染器的配置参数&#xff0c;可选。 …

启明智显ZX7981PC:5G时代的新选择,全屋网络无缝覆盖

在这个飞速发展的5G时代&#xff0c;每一个细微的科技进步都在推动着我们的生活向更加智能、便捷的方向发展。近日&#xff0c;启明智显再次引领科技潮流&#xff0c;正式发布其最新的5G CPE产品——ZX7981PC。作为继7981PG与7981PM之后的又一次迭代升级&#xff0c;ZX7981PC凭…

Qt控件的盒子模型,了解边距边线和内容区

这篇专门讲讲一个控件在绘制时的视觉样式。我们平常在对控件设置样式时&#xff0c;需要设置控件的一些外边距&#xff0c;内边距&#xff0c;边线&#xff0c;还有文字内容&#xff0c;贴上图片等。那么对于一个控件&#xff0c;到底怎么实现这些设置的呢&#xff1f; 先看下面…