当前位置: 首页 > article >正文

【Web前端】深入解析JavaScript异步编程

JavaScript的异步编程是其核心特性之一也是理解JavaScript运行机制的关键。下面我从几个方面详细介绍。一、为什么需要异步编程JavaScript 是单线程语言意味着同一时间只能做一件事。如果没有异步编程当遇到耗时操作如网络请求、文件读取、定时器时整个程序就会阻塞导致页面卡死无法响应。异步编程就是为了解决这个问题让耗时操作在后台执行不影响主线程继续处理其他任务。二、异步编程的演进历程1. 回调函数Callback最早的异步解决方案将函数作为参数传入在异步操作完成后执行。// 定时器回调 setTimeout(() { console.log(2秒后执行); }, 2000); // 事件回调 button.addEventListener(click, () { console.log(按钮被点击); }); // 传统的Ajax请求 function fetchData(callback) { // 模拟异步请求 setTimeout(() { callback(获取到的数据); }, 1000); } fetchData((data) { console.log(data); });☹ 问题回调地狱当多个异步操作有依赖关系时就会出现嵌套过深的问题fetchData((data1) { processData(data1, (data2) { validateData(data2, (data3) { saveData(data3, (result) { console.log(最终结果, result); }); }); }); });这种代码难以阅读、难以维护错误处理也很复杂。2. PromisePromise 是 ES6 引入的解决方案表示一个异步操作的最终完成或失败。// Promise 的基本使用 const promise new Promise((resolve, reject) { // 异步操作 setTimeout(() { const success true; if (success) { resolve(成功的数据); } else { reject(失败的原因); } }, 1000); }); promise .then(result { console.log(成功:, result); return result 处理; }) .then(processed { console.log(处理后的结果:, processed); }) .catch(error { console.log(失败:, error); }) .finally(() { console.log(无论成功失败都会执行); });★ Promise 的关键特性状态不可逆pending → fulfilled 或 pending → rejected一旦改变就不能再变链式调用通过.then()返回新的 Promise解决了回调地狱问题错误冒泡.catch()可以捕获链中任意一个 Promise 的错误// 用 Promise 改写上面的回调地狱 fetchData() .then(data1 processData(data1)) .then(data2 validateData(data2)) .then(data3 saveData(data3)) .then(result console.log(最终结果, result)) .catch(error console.error(出错了, error));☛ Promise 的静态方法// Promise.all所有都成功才成功一个失败就失败 Promise.all([fetch1(), fetch2(), fetch3()]) .then(results console.log(全部成功, results)); // Promise.race谁先完成就用谁的结果 Promise.race([fetch1(), fetch2()]) .then(result console.log(最快的那个, result)); // Promise.allSettled等待所有都完成无论成功或失败 Promise.allSettled([fetch1(), fetch2()]) .then(results console.log(所有结果, results)); // Promise.any任意一个成功就成功全部失败才失败 Promise.any([fetch1(), fetch2()]) .then(result console.log(第一个成功的, result));3. Generator 函数中间过渡方案Generator 可以暂停和恢复执行配合 Promise 可以实现类似同步的异步代码但使用起来不够直观。function* asyncGenerator() { const data1 yield fetchData(); const data2 yield processData(data1); return data2; } // 需要手动执行器或使用 co 库 function run(generator) { const it generator(); function next(value) { const result it.next(value); if (result.done) return result.value; result.value.then(next); } next(); } run(asyncGenerator);4. async/awaitES2017 引入的语法糖让异步代码写起来像同步代码。// async 函数总是返回 Promise async function getData() { try { const data1 await fetchData(); const data2 await processData(data1); const data3 await validateData(data2); const result await saveData(data3); console.log(最终结果, result); return result; } catch (error) { console.error(出错了, error); throw error; // 可以继续抛出 } } // 调用 getData() .then(result console.log(完成, result)) .catch(error console.error(捕获, error));☺async/await 的优势1代码更清晰像同步代码一样顺序执行2使用 try/catch 统一处理错误符合直觉3避免了 Promise 链式调用中可能出现的混乱★ 注意事项// ❌ 错误用法没有等待结果 async function badExample() { fetchData(); // 没有 await不会等待 console.log(这行会先执行); } // ✅ 正确用法 async function goodExample() { const data await fetchData(); console.log(data); } // ✅ 并发执行用 Promise.all 优化 async function concurrentExample() { // 同时发起不用等待 const promise1 fetchData1(); const promise2 fetchData2(); // 等待全部完成 const [data1, data2] await Promise.all([promise1, promise2]); console.log(data1, data2); }三、事件循环Event Loop理解异步编程必须理解 JavaScript 的事件循环机制。1. 核心概念JavaScript 运行时包含1调用栈同步代码执行的地方2任务队列存放异步任务回调的地方3事件循环不断检查调用栈是否为空为空则从队列中取任务执行2. 宏任务与微任务异步任务分为两种1宏任务MacroTasksetTimeout、setIntervalI/O 操作UI 渲染setImmediateNode.js2微任务MicroTaskPromise 的 then/catch/finallyasync/await 中 await 之后的代码MutationObserverqueueMicrotask3执行顺序① 执行同步代码② 清空所有微任务③ 执行一个宏任务④ 清空所有微任务重复 3-4console.log(1); // 同步 setTimeout(() { console.log(2); // 宏任务 }, 0); Promise.resolve().then(() { console.log(3); // 微任务 }); console.log(4); // 同步 // 输出顺序1, 4, 3, 2// 更复杂的例子 async function async1() { console.log(async1 start); // 同步 await async2(); // await 后面的代码会变成微任务 console.log(async1 end); // 微任务 } async function async2() { console.log(async2); // 同步 } console.log(script start); // 同步 setTimeout(() { console.log(setTimeout); // 宏任务 }, 0); async1(); new Promise((resolve) { console.log(promise1); // 同步 resolve(); }).then(() { console.log(promise2); // 微任务 }); console.log(script end); // 同步 // 输出顺序 // script start // async1 start // async2 // promise1 // script end // async1 end // promise2 // setTimeout四、实际应用场景1. 网络请求// 使用 fetch API async function getUserInfo(userId) { try { const response await fetch(/api/users/${userId}); if (!response.ok) throw new Error(请求失败); const data await response.json(); return data; } catch (error) { console.error(获取用户信息失败, error); throw error; } }2. 并发控制// 限制并发数量的函数 async function limitConcurrency(tasks, limit) { const results []; const executing []; for (const task of tasks) { const p Promise.resolve().then(() task()); results.push(p); if (limit tasks.length) { const e p.then(() executing.splice(executing.indexOf(e), 1)); executing.push(e); if (executing.length limit) { await Promise.race(executing); } } } return Promise.all(results); }3. 轮询async function poll(fn, interval, maxAttempts) { let attempts 0; while (attempts maxAttempts) { try { const result await fn(); if (result) return result; } catch (error) { console.log(第 ${attempts 1} 次尝试失败); } await new Promise(resolve setTimeout(resolve, interval)); attempts; } throw new Error(轮询超时); } // 使用 const data await poll( () fetchData(), 1000, // 间隔1秒 5 // 最多尝试5次 );五、常见陷阱与最佳实践1. 忘记 await// ❌ 错误没有 await函数立即返回 Promise 对象 async function getData() { fetchData(); // 忘记 await console.log(这行会先执行); } // ✅ 正确 async function getData() { const data await fetchData(); console.log(data); }2. 循环中的 await// ❌ 串行执行效率低 async function processItems(items) { for (const item of items) { await processItem(item); // 一个一个处理 } } // ✅ 并行执行 async function processItems(items) { const promises items.map(item processItem(item)); await Promise.all(promises); }3. 错误处理// ❌ 没有错误处理 async function riskyOperation() { const data await fetchData(); // 如果失败会抛出未捕获的异常 return data; } // ✅ 使用 try/catch async function safeOperation() { try { const data await fetchData(); return data; } catch (error) { console.error(操作失败, error); return null; // 返回默认值 } }4. 避免 Promise 构造器滥用// ❌ 不必要的 Promise 包装 function bad() { return new Promise((resolve, reject) { fetchData() .then(resolve) .catch(reject); }); } // ✅ 直接返回 Promise function good() { return fetchData(); }六、总结JavaScript 异步编程经历了从回调函数到 Promise再到 async/await 的演进越来越符合人类的思维方式。核心要点1异步是单线程 JavaScript 的必然选择2理解事件循环是掌握异步的关键3优先使用 async/await 编写异步代码4注意微任务和宏任务的执行顺序5合理处理错误和并发掌握了这些内容我们就能够应对绝大部分 JavaScript 异步编程的场景了。

相关文章:

【Web前端】深入解析JavaScript异步编程

JavaScript的异步编程是其核心特性之一,也是理解JavaScript运行机制的关键。下面我从几个方面详细介绍。一、为什么需要异步编程?JavaScript 是单线程语言,意味着同一时间只能做一件事。如果没有异步编程,当遇到耗时操作&#xff…...

Open WebUI:企业级自托管AI平台架构深度解析

Open WebUI:企业级自托管AI平台架构深度解析 【免费下载链接】open-webui Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 WebUI,设计用于完全离线操作,支持各种大型语言模型(LLM)运行器,包括Ollama…...

路径遍历 PortSwigger labs

File path traversal, simple case 实验信息 平台:PortSwigger Web Security Academy 漏洞:路径遍历漏洞(Path Traversal) Lab:Server-side vulnerabilities - PortSwigger 难度:简单 漏洞原理 网站通过 filena…...

提升网络调试效率,快马AI一键生成端口扫描与服务检测实用脚本

最近在调试网络服务时,经常需要手动检查端口状态和接口可用性,重复劳动特别耗时。于是尝试用Python写了个自动化工具,发现效果不错,分享下实现思路和使用体验。 端口扫描功能实现 通过socket模块实现基础的TCP连接检查&#xff0c…...

浮点数精度问题实战:如何用eps避免3.8的小数部分变成0.799999?

浮点数精度陷阱:从3.8的0.799999现象到工业级误差控制方案 当你在金融交易系统中发现0.01元的差额,或在游戏物理引擎中看到角色卡进墙壁,背后可能都是浮点数精度问题在作祟。最近团队在开发高频交易系统时,一个简单的价格计算3.8…...

Mac用户必看:OpenClaw一键安装百川2-13B-4bits量化模型指南

Mac用户必看:OpenClaw一键安装百川2-13B-4bits量化模型指南 1. 为什么选择这个组合? 上周我在调试一个自动化文档处理流程时,发现常规的7B模型在处理复杂表格时经常漏掉关键字段。在测试了多个开源模型后,百川2-13B的表格理解能…...

统计学顶刊投稿攻略:从JASA到Biometrika的写作风格差异详解

统计学顶刊投稿攻略:从JASA到Biometrika的写作风格差异详解 在统计学研究的星辰大海中,四大顶级期刊犹如指引方向的灯塔。JASA、JRSSB、Annals of Statistics和Biometrika各自拥有独特的学术气质和审稿偏好,理解这些差异往往决定着投稿的成败…...

微信聊天记录完全掌控指南:如何永久保存并深度分析你的数字记忆

微信聊天记录完全掌控指南:如何永久保存并深度分析你的数字记忆 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending…...

告别重复劳动,用快马平台生成powershell脚本大幅提升数据处理效率

告别重复劳动,用快马平台生成powershell脚本大幅提升数据处理效率 最近接手了一个需要定期汇总销售数据的任务,每个月都要手动合并几十个Excel文件,然后计算各种统计指标。这种重复性工作不仅耗时耗力,还容易出错。直到发现了Ins…...

挖到宝!PFC2D 流固耦合常用案例合集,科研人速进

该模型是“PFC2D流固耦合常用案例合集”: 其中包括水力压裂、达西渗流等多个案例。 有需要学习和交流的伙伴可按需选取。 干货满满,是运用pfc5.0做流固耦合必不可少的科研学习资料性价比绝对超高 内容可编辑,觉得运行通畅 代码真实有效。最近…...

快速生成node.js环境配置原型:用快马一键创建安装验证工具

快速生成node.js环境配置原型:用快马一键创建安装验证工具 最近在带新人入门Node.js开发时,发现很多小伙伴卡在了最基础的环境配置环节。不同操作系统下的安装方式差异、版本兼容性问题、环境变量配置这些看似简单的步骤,往往会消耗初学者大…...

云端存储本地化革新:从0到1掌握s3fs-fuse文件系统映射技术

云端存储本地化革新:从0到1掌握s3fs-fuse文件系统映射技术 【免费下载链接】s3fs-fuse FUSE-based file system backed by Amazon S3 项目地址: https://gitcode.com/gh_mirrors/s3/s3fs-fuse 在云计算时代,如何让云端存储像本地硬盘一样便捷访问…...

别再拍脑袋定A/B测试样本量了!用Python/Excel/R三分钟算出靠谱结果

别再拍脑袋定A/B测试样本量了!用Python/Excel/R三分钟算出靠谱结果 每次启动A/B测试前,团队总会陷入同样的争论:"这次实验需要多少流量才够?"产品经理凭经验说"10万用户应该够了",运营同学翻出上次…...

DiskInfo硬盘检测工具:3步掌握硬盘健康状态的智能监测方案

DiskInfo硬盘检测工具:3步掌握硬盘健康状态的智能监测方案 【免费下载链接】DiskInfo DiskInfo based on CrystalDiskInfo 项目地址: https://gitcode.com/gh_mirrors/di/DiskInfo 在数字化时代,硬盘作为数据存储的核心载体,其健康状态…...

5分钟部署Sambert语音合成:多情感中文TTS开箱即用,新手零门槛

5分钟部署Sambert语音合成:多情感中文TTS开箱即用,新手零门槛 1. 引言:为什么选择这个语音合成镜像 想象一下,你正在开发一个智能客服系统,需要让AI用不同的语气和音色与用户交流。传统语音合成方案要么配置复杂&…...

如何用铜钟音乐打造纯粹听歌体验?5个让你告别广告干扰的核心优势

如何用铜钟音乐打造纯粹听歌体验?5个让你告别广告干扰的核心优势 【免费下载链接】tonzhon-music 铜钟 (Tonzhon.com): 免费听歌; 没有直播, 社交, 广告, 干扰; 简洁纯粹, 资源丰富, 体验独特!(密码重置功能已回归) 项目地址: https://gitcode.com/Git…...

终极指南:如何永久解决IDM激活弹窗问题 - 完整技术方案

终极指南:如何永久解决IDM激活弹窗问题 - 完整技术方案 【免费下载链接】IDM-Activation-Script IDM Activation & Trail Reset Script 项目地址: https://gitcode.com/gh_mirrors/id/IDM-Activation-Script Internet Download Manager(IDM&a…...

手把手教你用Python写一个高效图片爬虫(附代码+反爬策略)

大家好!今天分享一个我近期开发的Python图片爬虫程序,适合新手入门和进阶学习。项目包含多线程下载、反反爬机制、数据存储等核心功能,代码已开源并附详细注释。 一、项目背景 在数据采集场景中,图片下载是常见需求。但目标网站…...

s3fs-fuse架构深度解析:如何通过FUSE实现云端存储的本地化操作

s3fs-fuse架构深度解析:如何通过FUSE实现云端存储的本地化操作 【免费下载链接】s3fs-fuse FUSE-based file system backed by Amazon S3 项目地址: https://gitcode.com/gh_mirrors/s3/s3fs-fuse 在现代云计算环境中,对象存储服务如Amazon S3已经…...

mybatis实战进阶:基于快马生成缓存、分页与批量处理等生产级配置

mybatis实战进阶:基于快马生成缓存、分页与批量处理等生产级配置 最近在做一个用户管理系统时,遇到了不少mybatis的性能问题。单表查询还好,一旦涉及关联查询和批量操作,性能瓶颈就特别明显。经过一番摸索,总结出几个…...

Spring Boot + JPA实战:RBAC权限管理系统从零搭建(附完整代码)

Spring Boot与JPA深度整合:构建企业级RBAC权限系统的实战指南 在当今企业应用开发中,权限管理是保障系统安全的核心组件。基于角色的访问控制(RBAC)模型因其清晰的权限分配逻辑和灵活的可扩展性,成为大多数系统的首选方案。本文将带您从零开始…...

终极指南:如何用Python脚本5分钟获取百度网盘真实下载链接

终极指南:如何用Python脚本5分钟获取百度网盘真实下载链接 【免费下载链接】baidu-wangpan-parse 获取百度网盘分享文件的下载地址 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wangpan-parse 你是否曾经为百度网盘的下载速度而烦恼?每次…...

2026年最新出炉!汉中装修公司口碑排行榜大揭秘来了!

装修是一件大事,关乎着未来生活的品质和舒适度。在汉中,众多装修公司让人眼花缭乱,如何选择一家靠谱的装修公司成为了许多业主的难题。今天,我们就来揭秘2026年汉中装修公司口碑排行榜,重点推荐汉中恒丰装饰&#xff0…...

新手前端第一课:在快马平台用ai生成一个属于自己的“notepad++”

作为一个刚接触前端开发的新手,我最近在InsCode(快马)平台上尝试做了一个简易版的文本编辑器,感觉特别适合用来理解基础的前端开发逻辑。整个过程就像搭积木一样有趣,现在把学习心得分享给大家。 项目构思阶段 我想做一个类似notepad的简易编…...

5分钟掌握OptiScaler:让所有显卡都能享受DLSS级画质的免费神器

5分钟掌握OptiScaler:让所有显卡都能享受DLSS级画质的免费神器 【免费下载链接】OptiScaler DLSS replacement for AMD/Intel/Nvidia cards with multiple upscalers (XeSS/FSR2/DLSS) 项目地址: https://gitcode.com/GitHub_Trending/op/OptiScaler 还在为显…...

远程办公团队如何高效协作:项目管理的10条黄金法则

远程办公团队如何高效协作?本文结合10年项目管理实践,总结出目标对齐、书面共识、责任分工、沟通节奏、进度透明、风险预警、反馈复盘和团队信任等10条黄金法则,帮助管理者提升远程协作效率与项目交付质量。 远程办公已经成为许多团队的常态协…...

别再踩坑了!UniApp集成支付宝支付,从创建应用到上线审核的保姆级避坑指南

UniApp集成支付宝支付全流程避坑指南:从密钥配置到审核上线的实战经验 第一次在UniApp项目中集成支付宝支付时,我花了整整三天时间反复调试——不是因为代码逻辑复杂,而是那些看似简单的配置环节处处是坑。本文将分享我从七个关键环节总结的…...

各工厂产能负荷不透明?SAP 集团生产模块实现服装多工厂协同生产

在服装企业规模化扩张过程中,多工厂布局成为提升产能、覆盖市场的重要选择,但 “各工厂产能负荷不透明” 却成为制约协同效率的关键瓶颈。很多服装集团面临这样的困境:总部不清楚 A 工厂的高端定制生产线是否饱和,B 工厂的批量生产…...

SD2.0时钟与时序:从基础模式到高速传输的实战解析

1. SD2.0时钟与时序基础入门 第一次接触SD2.0规范时,我也被那些密密麻麻的时序参数搞得头晕眼花。直到在项目里实际调试SD卡读写失败的问题后,才发现理解时钟和时序的配合有多重要。简单来说,时钟就像两个人对话的节奏,而时序则是…...

QIP 2023:亚马逊量子计算三篇论文突破

量子技术 某机构在QIP 2023发表的量子计算论文 针对“超级Grover”优化、拓扑数据分析的量子算法以及物理系统模拟的研究,展示了某机构在量子计算领域的广泛兴趣。 作者: Fernando Brando 日期: 2023年2月2日 阅读时间: 7分钟 在今…...