现代 Web 开发严重依赖异步活动来实现响应式、交互式应用程序。无论是从 API 检索数据、读取文件还是运行计时器,这些进程都必须在后台运行,而不会冻结界面。 JavaScript 为您提供了一种可靠的方式来处理这些工作。本文涵盖了您需要了解的有关 Promise 的所有信息,包括基本思想和高级功能,以开发无错误的异步程序。
在本文中您将了解 —
什么是 Promise?
为什么使用 Promise?
Promise 如何运作?
处理 Promise
连锁承诺
Promise 中的错误处理
高级 Promise 功能
带有 Promise 的 JavaScript 执行流程(重要)
将 Promise 链转换为异步/等待
最佳实践和常见错误
什么是承诺?
JavaScript 中的 Promise 相当于做出“承诺”在未来做某事。当你做出承诺时,你就是在说:“我保证稍后会给你结果。”这个结果可能是成功,也可能是失败。
换句话说,Promise 是一个反映异步操作最终成功(或失败)及其结果值的对象。它允许您将处理程序与异步操作的成功或失败关联起来,使您的代码更易于阅读和维护。
为什么使用 Promise?
例如,在 JavaScript 中,耗时的操作(例如从服务器检索数据)通常是通过回调完成的。回调只是一个传递给另一个函数以在任务完成后执行的函数。例如,您可以使用回调来处理来自服务器的数据。
但是,当有复杂的操作时,回调的使用就变得相当混乱。这种混乱被称为“回调地狱”,其中一个可以在另一个中进行回调,这使得代码不可读且难以管理。
回调地狱示例:
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
如上所示,由于其深层嵌套结构(通常称为“回调地狱”),此类代码在较大的代码库中变得越来越难以阅读和维护。
引入 Promise 来解决这个问题,通过允许以更易读的方式进行链接,提供一种更干净、更有组织的方式来处理异步任务。
基于承诺的方法:
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
这种方法扁平化了结构,使代码更具可读性和可维护性。
承诺如何发挥作用?
JavaScript 中的 Promise 可以处于以下三种状态之一:
待处理:这是第一步。承诺还没有兑现。
Fulfilled:Promise 已成功完成,这意味着它已解决并且具有价值。
已拒绝:Promise 未成功完成,并且带有错误消息。
基本语法
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
在此示例中,promise 在 1 秒后解析,并显示消息“Promise returned!”。 .then() 方法用于处理解析后的值。
处理承诺
使用 .then() 进行成功处理
.then()方法用于处理promise成功完成时发生的情况。它注册函数(回调)以在承诺完成时运行。
const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve("Promise resolved!"); }, 1000); }); myPromise.then(result => console.log(result));
使用 .catch() 进行错误处理
.catch()方法用于处理promise失败时发生的情况。它注册一个函数(回调)以在 Promise 被拒绝时运行。
myPromise.then(data => { console.log("Data received:", data); });
使用 .finally() 进行清理
.finally() 方法可以让你在 Promise 完成后运行一些代码,无论成功与否。
myPromise.catch(error => { console.error("Error:", error); });
链接承诺
链接允许您通过传递前一个任务的结果来顺序执行任务。然后继续进行next.then()。这允许您按顺序处理多个异步任务。
链接示例:
myPromise.finally(() => { console.log("Cleanup tasks"); });
此示例使用each.then()来处理流程中的每个步骤,从而实现清晰的数据流。这可以让您看到一个阶段的结果如何转移到下一阶段。
Promise 中的错误处理
Promise 通过允许它们将链向下传递给 .catch() 方法来解决,从而简化了错误处理。这消除了在每个阶段处理失败的需要,使您的代码更清晰且更易于管理。
错误传播示例:
fetch('https://api.example.com/user') .then(response => response.json()) .then(data => { console.log("Processed data:", data); return processData(data); }) .then(finalResult => { console.log("Final result:", finalResult); }) .catch(error => console.error("Error:", error));
如果 Promise 链中的任何一步失败,错误将被 .catch() 块捕获。这使得您可以轻松处理问题并保持代码顺利运行。
高级 Promise 功能
1. Promise.all() 用于并行执行
Promise.all() 方法允许您同时运行多个 Promise 并等待它们全部完成。如果所有承诺都得到履行,您将收到每一项承诺的结果。如果任何承诺失败,它会检测到错误。
fetchData() .then(processData) .then(saveData) .catch(error => console.error("An error occurred:", error));
在此示例中,如果任何 Promise 失败,则整个 Promise.all() 都会失败。
2. Promise.race() 实现最快的 Promise
Promise.race() 方法返回第一个完成的 Promise 的结果,无论成功还是失败。
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
在此示例中,无论哪个 Promise(fetchData1 或 fetchData2)先完成,其结果都会记录到控制台。
3. Promise.allSettled() 用于处理所有结果
Promise.allSettled()方法等待你给它的所有promise都处于成功或失败状态,然后完成。然后返回一个数组,其中包含每个承诺的结果。
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
在此示例中,Promise.allSettled() 等待 fetchData1() 和 fetchData2() 完成。然后它记录每个承诺的状态和结果(或错误)。这样,您就可以看到每个 Promise 发生了什么,无论它们是成功还是失败。
4.Promise.any() 用于解决第一个成功的 Promise
Promise.any() 方法等待 Promise 列表中的第一个 Promise 被正确解析。如果至少有一个 Promise 得到解决,则 Promise.any() 方法将返回该值。如果所有的 Promise 都被拒绝,这个方法将会抛出一个错误。
const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve("Promise resolved!"); }, 1000); }); myPromise.then(result => console.log(result));
在此示例中,Promise.any() 等待第一个 Promise 成功解析。该过程返回第一个成功的 Promise 的结果,在本例中,promise2 的值为“Success A”。如果所有承诺都被拒绝,则执行 .catch() 块,并记录错误消息。当您想要收到第一个成功的 Promise 的结果而不必等待其余的结果时,此策略非常有用。
带有 Promise 的 JavaScript 执行流程(重要)
1. JavaScript 中的 Promise 在微任务队列中运行,其优先级高于 setTimeout 等宏任务。
这里有一个例子来说明这一点:
myPromise.then(data => { console.log("Data received:", data); });
在此示例中:
console.log(2) 首先运行,因为它是常规同步操作。
console.log (6) 接下来运行,因为它也是同步的。
promise 的.then() 在 setTimeout 回调之前运行,因为 Promise 是微任务,具有更高的优先级,因此打印 3.
最后,setTimeout 回调运行,因为它是一个宏任务并打印 4。
所以永远记住,由于微任务队列的优先级,promise's.then() 在 setTimeout 回调之前执行。
2. Promise 执行顺序和具有多个 .then() 调用的微任务队列
在 JavaScript 中,代码按特定顺序运行:首先是同步代码,然后是微任务(如 Promise),最后是宏任务(如 setTimeout)。
这里有一个例子来解释这一点:
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
在此示例中,同步代码首先运行,记录 3、6、2、7 和 8。同步代码完成后,将处理微任务(then() 回调),记录 1 和 9。最后,宏任务(来自 setTimeout)按延迟顺序执行,记录 21 (0ms) 和 13 (10ms)。这突出了 JavaScript 的执行顺序:同步代码 >微任务>宏任务。
3. Promise 中的多个 Resolve 和 Reject 调用:只有第一个很重要
当您创建承诺时,第一个解决或拒绝的调用是唯一重要的。所有其他呼叫均被驳回。
这里有一个例子来说明这一点:
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
在此示例中,promise 使用值 1 进行解析。第二个解析和拒绝调用将被忽略,因为 Promise 已通过第一个解析进行结算。
4. 在连续的 .then() 调用中链接 Promise 并处理值
当你链接 Promise 时,each.then() 会处理流程中的一个步骤。
const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve("Promise resolved!"); }, 1000); }); myPromise.then(result => console.log(result));
在此示例中,Promise.resolve(1) 以值 1 开头,但第一个 .then(() => 2) 返回 2。下一个 .then(3) 被忽略,并且值 2 被传递。 .then((value) => value * 3) 将值乘以 3,结果是 6。.then(Promise.resolve(4)) 不会更改值,最后,.then(console. log)logs 6。这演示了值如何通过链传递,非函数值被忽略。
5. 使用 .catch() 和 .finally() 处理的 Promise 链
myPromise.then(data => { console.log("Data received:", data); });
在此示例中,我们将多个 .then()、.catch() 和 .finally() 方法链接在一起,以展示如何处理 Promise 解析的不同阶段。让我们来分解一下:
finally() 没有收到参数:
finally() 块执行清理代码,但不接受或传递任何值。它用于确保某些代码运行,无论承诺的结果如何。在finally()中返回一个值不会影响promise:
如果您在finally()块中返回一个值,它不会影响promise链或最终值。它在承诺解决/拒绝后执行,但不会修改结果。在finally()中抛出错误会导致拒绝:
如果你在finally()中抛出错误或者返回被拒绝的promise,将会导致promise链被拒绝,并带有错误或者拒绝原因。
myPromise.catch(error => { console.error("Error:", error); });
或者
myPromise.finally(() => { console.log("Cleanup tasks"); });
- then() 和 catch() 的顺序很重要 .then() 和 .catch() 可以按任何顺序调用,但它们将始终返回 Promise 的最终状态。当 .catch() 处理 Promise 时,任何后续的 .then() 将收到最终值。
示例:
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
将 Promise 链转换为 Async/Await
Async/await 是一种使用 Promise 的方法,使代码变得更像以同步模式编写的代码。经常使用的术语是“语法糖”,因为它提供了一种更直接、更清晰的异步代码执行路径。
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
将 Promise 与 Async/Await 相结合
您可以使用 Promise.all() 将 Promise 与 async/await 结合起来以实现并行执行。
const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve("Promise resolved!"); }, 1000); }); myPromise.then(result => console.log(result));
最佳实践和常见错误
避免深层嵌套:使用链接或异步/等待来保持代码平坦和可读。
始终处理错误: 确保每个 Promise 链都有 a.catch() 或 try/catch 块。
明智地使用并行执行:仅当任务独立但需要一起完成时才使用 Promise.all()。
结论
JavaScript Promise 是处理耗时操作(例如在服务器上检索数据)的最佳方法之一。它们甚至可以帮助您编写更清晰、更易于维护的代码,并且您所学知识的实践将使您能够充分利用异步编码。一旦你获得了一些实践经验并开始优雅地处理错误,Promise 将成为 JavaScript 的重要组成部分。
感谢您的阅读!如果您觉得这篇文章有帮助,请随时突出显示、鼓掌、发表评论,甚至在 Twitter/X 和 LinkedIn 上与我联系,因为我非常感激并帮助保持此类内容免费!
以上是关于 JavaScript Promise 及其工作原理,您需要了解的一切的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。