JavaScript异步数据缓存:实现单次查询与数据复用

JavaScript异步数据缓存:实现单次查询与数据复用

本文探讨了如何在JavaScript异步编程中避免重复的数据库查询,实现数据的高效复用。通过介绍空值合并赋值运算符(??=)结合Promise的延迟初始化机制,我们将展示如何仅执行一次异步数据获取操作,并将返回的Promise对象缓存起来,供后续函数重复使用,从而显著提升应用性能并减少数据库负载。

异步数据获取中的重复查询问题

在现代web应用开发中,与数据库或其他外部api进行异步交互是常见的操作。为了优化性能和减少服务器负载,我们通常希望对相同的数据只进行一次查询,然后将结果缓存起来供后续函数使用。然而,在不恰当的实现下,我们可能会遇到重复查询的问题。

考虑以下JavaScript代码片段,它尝试通过一个全局变量来缓存异步获取的数据:

async function GetCoverage(scroll_path) {  // 模拟一个异步DB或API调用  console.log(`Executing GetCoverage for: ${scroll_path}`);  return new Promise(resolve => {    setTimeout(() => {      resolve([{ id: 1, path: scroll_path, data: Math.random() }]);    }, 500);  });}let dataGlobal; // 用于存储数据或Promiseconst getData = async () => {  const response = await GetCoverage("all"); // 每次调用都会触发GetCoverage  dataGlobal = response;  return response;};(async () => {  console.log("Initial call to getData...");  await getData();  console.log("dataGlobal after first call:", dataGlobal);  console.log("nSecond call to getData...");  await getData(); // 这会再次调用GetCoverage  console.log("dataGlobal after second call:", dataGlobal);})();

在上述代码中,getData 函数每次被调用时,都会执行 await GetCoverage(“all”),这意味着无论 dataGlobal 是否已经有值,GetCoverage 函数(模拟数据库查询)都会被重新触发。这导致了不必要的数据库查询,浪费了资源并增加了响应时间。

解决方案:Promise的延迟初始化与缓存

为了解决重复查询的问题,我们需要一种机制来:

延迟初始化:仅在数据首次被请求时才执行异步查询。缓存Promise:将异步查询返回的 Promise 对象缓存起来,而不是等待它解析后的数据。这样,后续的请求可以直接返回这个已缓存的 Promise,无论它是处于待定(pending)、已解决(resolved)还是已拒绝(rejected)状态。

JavaScript中的空值合并赋值运算符 (??=) 提供了一种简洁高效的方式来实现这一目标。

立即学习“Java免费学习笔记(深入)”;

空值合并赋值运算符 (??=) 简介

??= 运算符是一个逻辑赋值运算符。它的语法是 a ??= b,等同于 a = a ?? b。这意味着如果 a 是 null 或 undefined(即“空值”),那么 a 将被赋值为 b 的值;否则,a 的值保持不变。

利用 ??= 运算符的这一特性,我们可以非常优雅地实现Promise的延迟初始化和缓存。

实现单次查询与数据复用

我们将 dataGlobal 变量用于存储 GetCoverage 返回的 Promise。getData 函数的职责将变为:如果 dataGlobal 尚未被赋值(即为 undefined 或 null),则调用 GetCoverage 并将其返回的 Promise 赋值给 dataGlobal;否则,直接返回 dataGlobal 中已存在的 Promise。

// 假设 GetCoverage 函数已定义,与上面示例相同async function GetCoverage(scroll_path) {  console.log(`Executing GetCoverage for: ${scroll_path}`);  return new Promise(resolve => {    setTimeout(() => {      resolve([{ id: 1, path: scroll_path, data: Math.random() }]);    }, 500);  });}let dataGlobalPromise; // 用于存储GetCoverage返回的Promiseconst getData = () => (dataGlobalPromise ??= GetCoverage("all")); // 核心优化// 演示如何使用(async () => {  console.log("Making parallel calls to getData...");  // 第一次调用 getData() 会触发 GetCoverage("all")  // 并将返回的 Promise 赋值给 dataGlobalPromise  const result1Promise = getData();  // 第二次调用 getData() 会直接返回 dataGlobalPromise 中已有的 Promise  const result2Promise = getData();  // 第三次调用 getData() 同样直接返回已有的 Promise  const result3Promise = getData();  // 等待所有 Promise 解析  const [result1, result2, result3] = await Promise.all([    result1Promise,    result2Promise,    result3Promise  ]);  console.log("Result #1:", result1);  console.log("Result #2:", result2);  console.log("Result #3:", result3);  console.log("nConfirming dataGlobalPromise content:", dataGlobalPromise);  // 再次调用 getData,验证 GetCoverage 不会再次执行  console.log("nCalling getData again to verify no new GetCoverage execution...");  const result4 = await getData();  console.log("Result #4:", result4);})();

代码解析:

let dataGlobalPromise;:声明一个变量,初始值为 undefined。const getData = () => (dataGlobalPromise ??= GetCoverage(“all”));:这是核心所在。首次调用 getData() 时:dataGlobalPromise 是 undefined,满足 ??= 的条件。GetCoverage(“all”) 会被执行,返回一个 Promise 对象。这个 Promise 对象随后被赋值给 dataGlobalPromise,并作为 getData 函数的返回值。此时,控制台会输出 Executing GetCoverage for: all。后续调用 getData() 时:dataGlobalPromise 已经包含了之前赋值的 Promise 对象(无论它是否已解决)。此时 dataGlobalPromise 不再是空值,因此 ??= 运算符的右侧表达式 GetCoverage(“all”) 不会被执行。getData 函数直接返回 dataGlobalPromise 中已存在的 Promise 对象。控制台不会再次输出 Executing GetCoverage for: all。

通过这种方式,无论 getData 被调用多少次,GetCoverage 函数(模拟数据库查询)都只会被执行一次。所有对 getData 的调用都会返回同一个 Promise 对象,它们最终都会解析出相同的数据。

优势与注意事项

优势

性能提升:显著减少了不必要的数据库或API查询,降低了服务器负载,提高了应用程序的响应速度。代码简洁:使用 ??= 运算符使缓存逻辑变得非常紧凑和易读。并发处理:即使多个函数同时请求数据,它们也会共享同一个 Promise,避免了竞态条件和重复工作。

注意事项

错误处理:如果 GetCoverage 函数返回的 Promise 被拒绝(例如,数据库连接失败),那么 dataGlobalPromise 将会是一个被拒绝的 Promise。所有后续调用 getData().then(…) 的 catch 块都将捕获到这个错误。这是期望的行为,但需要确保你的代码能够正确处理这种情况。数据时效性:这种方法实现了永久缓存,除非应用程序重启或手动清除 dataGlobalPromise。如果数据需要定期刷新或根据某些条件失效,你需要额外的逻辑来重置 dataGlobalPromise(例如,将其设为 undefined 或 null),以便下次调用 getData 时能重新获取数据。作用域:dataGlobalPromise 变量的声明位置决定了缓存的作用域。在模块顶级声明它,可以使其在整个模块生命周期内有效。如果希望缓存仅在特定组件或类实例中有效,则应将其作为组件状态或类属性进行管理。

总结

通过巧妙地结合JavaScript的空值合并赋值运算符 (??=) 和Promise机制,我们可以高效地实现异步数据的单次查询与多处复用。这种模式在需要缓存异步操作结果以避免重复执行的场景中非常有用,例如获取配置信息、用户会话数据或任何不经常变动且需要全局访问的数据。理解并应用这种模式,能够显著优化应用程序的性能和资源利用效率。

以上就是JavaScript异步数据缓存:实现单次查询与数据复用的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1525088.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
动态添加表格行中下拉选择ID的获取与处理
上一篇 2025年12月20日 17:22:28
如何利用JavaScript的Proxy对象实现高级数据绑定?
下一篇 2025年12月20日 17:22:35

相关推荐

  • 高效整合Spikkl地理位置数据:利用Composer简化API调用

    最近我接手了一个项目,需要根据用户提供的邮政编码或经纬度信息获取详细的地址信息。最初,我直接使用curl处理spikkl api,代码冗长且难以维护,异常处理也十分繁琐。面对不断增加的功能需求,这种方式变得越来越难以支撑。这时,我意识到需要一个更优雅、更高效的解决方案。 幸运的是,Spikkl 提供…

    用户投稿 2026年9月4日
    100
  • 如何用代码实现精准切换指定程序窗口?

    程序窗口精准切换的代码实现方法 在日常电脑操作中,我们经常需要在不同的程序窗口间切换,Alt+Tab是常用的快捷键。但如果需要更精确地控制,例如只切换到特定程序的窗口,则需要借助代码实现。 实现步骤: 此方法的核心在于三个Windows API函数: 获取窗口句柄 (FindWindow): 使用F…

    2026年9月4日
    000
  • 人工智能会彻底改变药物研发吗?这取决于如何使用

    人工智能会彻底改变药物研发吗?这取决于如何使用人工智能会彻底改变药物研发吗?这取决于如何使用人工智能会彻底改变药物研发吗?这取决于如何使用人工智能会彻底改变药物研发吗?这取决于如何使用

    人工智能在药物研发领域的应用:机遇与挑战并存 人工智能(AI)在药物研发中的潜力引发了广泛关注,但其作用究竟如何仍存在争议。一些人认为AI将彻底改变药物研发,而另一些人则持谨慎态度,认为AI的实际效果还有待验证。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek…

    2026年9月4日 用户投稿
    100
  • [C++]在windows基于C++编程署yolov8的openvino目标检测模型cmake项目部演示源码

    在#%#$#%@%@%$#%$#%#%#$%@_0f4137ed1502b5045d6083aa258b5c++42平台上,利用c++结合openvino部署yolov8目标检测模型,可以通过cmake构建项目实现高效推理。yolov8作为yolo系列的较新版本,在检测精度与推理速度方面均有显著提升…

    2026年9月4日
    000
  • Apertus— 瑞士开源的首个大规模语言模型

    Apertus— 瑞士开源的首个大规模语言模型Apertus— 瑞士开源的首个大规模语言模型Apertus— 瑞士开源的首个大规模语言模型Apertus— 瑞士开源的首个大规模语言模型

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 天工大模型 中国首个对标ChatGPT的双千亿级大语言模型 115 查看详情 Apertus是什么 apertus是瑞士epfl、eth zurich和瑞士国家超级计算中心(cscs)联合推出的…

    2026年9月4日 用户投稿
    100
  • VSCode怎么弄颜色_VSCode自定义语法高亮和主题颜色教程

    自定义VSCode颜色需通过settings.json文件,结合主题扩展与个性化设置。首先安装喜欢的颜色主题,再通过workbench.colorCustomizations调整UI元素(如侧边栏、状态栏),使用editor.tokenColorCustomizations修改代码语法高亮,包括通用…

    2026年9月4日
    000
  • B站接入千问3,618期间商单成交效率提升5倍以上

    记者了解到,b站已经接入阿里巴巴的通义千问3(简称“千问3”)及其视觉语言模型vl等大模型,用于构建数据洞察智能体insightagent,旨在提升“花火”和“必达”等商业平台的工作效率。据悉,在618购物节期间,花火平台的商单成交效率提升了5倍以上,而必达的数据分析效率则提高了3倍以上。 作为B站…

    2026年9月4日
    100
  • Java远程调试(Remote Debugging)的那些事

    前言本文将探讨如何处理和调试那些仅在生产环境(或其他远程环境)中发生,而本地开发环境无法重现的“问题”。任何遇到这种情况的人都必须承认,试图找出这种“问题”原因的过程,很可能以一堆无根据的猜测告终:这是一个非常耗时且效率低下的过程。 还有一种情况,你得到了一个可以部署的war/jar包,只有clas…

    2026年9月4日
    000
  • AI for Science:北大、东方理工等团队用人工智能在实验数据中挖掘潜在规律

    AI for Science:北大、东方理工等团队用人工智能在实验数据中挖掘潜在规律AI for Science:北大、东方理工等团队用人工智能在实验数据中挖掘潜在规律AI for Science:北大、东方理工等团队用人工智能在实验数据中挖掘潜在规律AI for Science:北大、东方理工等团队用人工智能在实验数据中挖掘潜在规律

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 编辑 | ScienceAI‍‍ 科学研究的核心之一是发现能够描述自然现象的规律性方程。这些方程不仅能加深我们对自然的理解,还能为复杂问题的解决提供明确指导。 然而,许多领域,尤其是材料和化学等…

    2026年9月4日 用户投稿
    000
  • Maven pom.xml 中的资源配置:如何有效管理JAR包中的资源文件?

    Maven项目中pom.xml资源配置的最佳实践 在Maven构建过程中,pom.xml文件中的元素扮演着至关重要的角色,它负责将项目资源文件打包到最终的JAR包中。虽然Maven默认会包含一些特定目录下的资源,但显式配置元素仍然是最佳实践,这主要出于以下几个原因: 1. 明确指定资源目录: 通过元…

    2026年9月4日
    100
  • 告别繁琐的字符串处理:使用 Composer 简化你的 PHP 项目

    最近我负责一个 laravel 项目,需要处理用户提交的数据,其中包含各种非 ascii 字符,例如中文、日文、特殊符号等等。这些字符导致我的程序在进行字符串操作时效率低下,并且容易出现编码错误。我尝试了多种方法,例如使用 mb_string 函数,但效果并不理想,代码也变得冗长且难以维护。 为了解…

    用户投稿 2026年9月4日
    000
  • Beego框架提示“’GetSysStatus’方法不存在”错误如何解决?

    Beego框架报错:“’GetSysStatus’方法不存在”的排查与修复 在使用Beego框架进行开发时,如果遇到“’GetSysStatus’ method doesn’t exist”错误,通常表示你的代码中缺少名为GetSysSta…

    2026年9月4日
    000
  • Altman:OpenAI无意控告DeepSeek

    openai ceo sam altman否认了起诉中国初创公司deepseek的计划,尽管deepseek被指控“蒸馏”openai的技术。altman表示,openai将专注于持续开发领先的ai模型,而不是诉讼。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSe…

    2026年9月4日
    000
  • 《失落星船:马拉松》宣布延期发售 需更多时间准备

    射击游戏《失落星船:马拉松》原计划于今年9月24日正式上线,但bungie近日宣布该游戏将延期发布,新的发售时间将在今年秋季晚些时候公布。官方表示希望利用更多时间,将《马拉松》打造成真正能回应玩家期待的精品。 官方发表声明称:“我们通过社交媒体收到了大量反馈,这些声音对我们非常重要。我们也意识到,《…

    2026年9月4日
    200
  • 解决PHP Web应用数据更新延迟:浏览器缓存管理与实时内容展示

    本文深入探讨了PHP应用在本地开发环境中,当JSON数据或图片文件更新后,Web视图未能及时反映最新内容的问题。核心原因在于浏览器缓存机制。文章将详细介绍多种有效的解决方案,包括利用查询参数强制缓存失效、通过修改文件名实现版本控制,以及配置服务器端的缓存策略,旨在帮助开发者确保Web应用能够准确、实…

    2026年9月4日
    000
  • 英特尔大师挑战赛第一赛季圆满收官:全民电竞时代的新标杆

    英特尔大师挑战赛第一赛季圆满收官:全民电竞时代的新标杆英特尔大师挑战赛第一赛季圆满收官:全民电竞时代的新标杆英特尔大师挑战赛第一赛季圆满收官:全民电竞时代的新标杆英特尔大师挑战赛第一赛季圆满收官:全民电竞时代的新标杆

    随着《永劫无间》最后一场决胜局的画面在大赛屏幕上定格,英特尔大师挑战赛(IMC)第一赛季以一场堪称电竞里程碑式的巅峰对决圆满落下帷幕。今年赛事延续了网咖赛-大区赛-总决赛的三层晋级机制,同时为了提升公平性和观赏性,新增“双败淘汰制”与“天选之人积分制”,让更多因失误落败的强队有机会重返赛场。此外,决…

    2026年9月4日 用户投稿
    100
  • 免费PPT生成支持动画吗_免费工具实现PPT动画的技巧

    免费PPT工具可通过AI自动生成动画、手动设置或导出为GIF实现生动效果。1、使用Gamma.app或Canva等在线平台,输入描述语自动生成带动画的幻灯片;2、在LibreOffice Impress中通过“自定义动画”功能精细控制进入、强调与退出效果;3、将Google Slides等工具制作的…

    2026年9月4日
    100
  • C++中如何实现私有函数仅供特定公有函数调用?

    C++:限制私有函数的访问权限 如何确保C++中的私有成员函数只能被特定的公有成员函数访问,而其他函数无法直接调用? 在C++中,这可以通过巧妙地利用类的成员函数和作用域来实现。 私有成员函数本身就具有私有访问权限,这意味着只有类内部的成员函数才能访问它。 要实现“特定公有函数”的访问限制,我们不需…

    2026年9月4日
    000
  • 三六零与青岛市人民政府签署战略合作协议 推动大模型落地应用

    近日,青岛市人民政府与三六零数字安全科技集团有限公司(以下简称360公司)在青岛正式签署战略合作协议。双方将在共建青岛城市数字安全运营中心、推动城市应用大模型发展、加强网络安全建设、人才培养及生态合作等方面展开深入协作。青岛市人民政府市委副书记、市长任刚、360集团创始人周鸿祎等出席签约仪式并见证这…

    2026年9月4日
    100
  • 多家车企开始在美部署充电网 包括现代宝马本田奔驰

      近日,韩国现代汽车宣布,其与宝马、通用、本田、奔驰、斯特兰蒂斯、丰田等全球汽车巨头共同成立的电动汽车充电合资企业“ionna”已在美国北卡罗来纳州的达勒姆总部举行开业仪式,标志着ionna正式开始在全美范围内部署充电网络。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 D…

    2026年9月4日
    100

发表回复

登录后才能评论
关注微信