现代 Web 开发严重依赖异步活动来实现响应式、交互式应用程序。无论是从 API 检索数据、读取文件还是运行计时器,这些进程都必须在后台运行,而不会冻结界面。 JavaScript 为您提供了一种可靠的方式来处理这些工作。本文涵盖了您需要了解的有关 Promise 的所有信息,包括基本思想和高级功能,以开发无错误的异步程序。
在本文中您将了解 —
什么是 Promise?
为什么使用 Promise?
Promise 如何运作?
处理 Promise
连锁承诺
Promise 中的错误处理
高级 Promise 功能
带有 Promise 的 JavaScript 执行流程(重要)
将 Promise 链转换为异步/等待
最佳实践和常见错误
JavaScript 中的 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()方法用于处理promise成功完成时发生的情况。它注册函数(回调)以在承诺完成时运行。
const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve("Promise resolved!"); }, 1000); }); myPromise.then(result => console.log(result));
.catch()方法用于处理promise失败时发生的情况。它注册一个函数(回调)以在 Promise 被拒绝时运行。
myPromise.then(data => { console.log("Data received:", data); });
.finally() 方法可以让你在 Promise 完成后运行一些代码,无论成功与否。
myPromise.catch(error => { console.error("Error:", error); });
链接允许您通过传递前一个任务的结果来顺序执行任务。然后继续进行next.then()。这允许您按顺序处理多个异步任务。
链接示例:
myPromise.finally(() => { console.log("Cleanup tasks"); });
此示例使用each.then()来处理流程中的每个步骤,从而实现清晰的数据流。这可以让您看到一个阶段的结果如何转移到下一阶段。
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.all() 方法允许您同时运行多个 Promise 并等待它们全部完成。如果所有承诺都得到履行,您将收到每一项承诺的结果。如果任何承诺失败,它会检测到错误。
fetchData() .then(processData) .then(saveData) .catch(error => console.error("An error occurred:", error));
在此示例中,如果任何 Promise 失败,则整个 Promise.all() 都会失败。
Promise.race() 方法返回第一个完成的 Promise 的结果,无论成功还是失败。
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
在此示例中,无论哪个 Promise(fetchData1 或 fetchData2)先完成,其结果都会记录到控制台。
Promise.allSettled()方法等待你给它的所有promise都处于成功或失败状态,然后完成。然后返回一个数组,其中包含每个承诺的结果。
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
在此示例中,Promise.allSettled() 等待 fetchData1() 和 fetchData2() 完成。然后它记录每个承诺的状态和结果(或错误)。这样,您就可以看到每个 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 的结果而不必等待其余的结果时,此策略非常有用。
这里有一个例子来说明这一点:
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 回调之前执行。
在 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 的执行顺序:同步代码 >微任务>宏任务。
当您创建承诺时,第一个解决或拒绝的调用是唯一重要的。所有其他呼叫均被驳回。
这里有一个例子来说明这一点:
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
在此示例中,promise 使用值 1 进行解析。第二个解析和拒绝调用将被忽略,因为 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。这演示了值如何通过链传递,非函数值被忽略。
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"); });
示例:
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
Async/await 是一种使用 Promise 的方法,使代码变得更像以同步模式编写的代码。经常使用的术语是“语法糖”,因为它提供了一种更直接、更清晰的异步代码执行路径。
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
您可以使用 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中文网其他相关文章!