JavaScript、异步编程和 Promises

2025-06-04

JavaScript、异步编程和 Promises

在本教程中,您将了解 JS 中的 Promise 是什么、JavaScript Promise 可以处于哪些状态,以及如何处理 JS Promise 中的异步错误。

到目前为止,您只处理常规值。您创建了一个变量或常量,保存了一些内容,然后就可以立即使用了。例如,您可以将其打印到控制台。

但是,如果值不是立即出现,而是需要先经过一段时间,该怎么办?我们经常从数据库或外部服务器获取数据。这些操作需要时间,有两种方法可以处理它们:

  • 我们可以尝试阻止程序的执行,直到我们收到数据
  • 或者我们可以继续执行,稍后在数据出现时处理

这并不是说一种方法一定比另一种更好。两者都适合不同的需求,因为我们在不同情况下需要不同的行为。

如果您等待的数据对于后续操作至关重要,那么您需要阻止执行,这是无法回避的。而如果您可以推迟处理,那么当然就不值得浪费时间,因为您可以做其他事情。

JavaScript Promise 到底是什么?

Promise是一种特殊类型的对象,可以帮助您处理异步操作。

在无法立即检索值的情况下,许多函数将向您返回承诺。

const userCount = getUserCount();

console.log(userCount); // Promise {<pending>}
Enter fullscreen mode Exit fullscreen mode

在这种情况下,getUserCount是返回的函数Promise。如果我们尝试立即显示变量的值userCount,我们会得到类似这样的结果Promise {<pending>}

会发生这种情况,因为目前还没有数据,我们需要等待。

JavaScript 中的 Promise 状态

承诺可以处于多种状态:

  • 待处理- 响应尚未准备好。请等待。
  • 已完成- 响应已准备就绪。成功。获取数据。
  • 已拒绝- 发生错误。请处理。

在pending状态下,我们无法做任何有用的事情,只能等待。在其他情况下,我们可以添加处理函数,当 Promise 进入 fulfilled 或 rejected 状态时调用这些函数。

为了处理数据的成功接收,我们需要一个then函数。

const userCount = getUserCount();
const handleSuccess = (result) => {
  console.log(`Promise was fulfilled. Result is ${result}`);
}

userCount.then(handleSuccess);
Enter fullscreen mode Exit fullscreen mode

对于错误处理 - catch

const handleReject = (error) => {
  console.log(`Promise was rejected. The error is ${error}`);
}

userCount.catch(handleReject);
Enter fullscreen mode Exit fullscreen mode

请注意,该getUserCount函数返回一个 Promise,因此我们不能直接使用userCount。为了在数据出现时对其进行一些有用的处理,我们需要向then和 函数添加处理程序catch,这些处理程序将在成功或错误时被调用。

then函数catch可以顺序调用。在这种情况下,我们将同时处理成功和失败的情况。

const userCount = getUserCount();
const handleSuccess = (result) => {
  console.log(`Promise was fulfilled. Result is ${result}`);
}

const handleReject = (error) => {
  console.log(`Promise was rejected. The error is ${error}`);
}

userCount.then(handleSuccess).catch(handleReject);
Enter fullscreen mode Exit fullscreen mode

JS Promise 中的错误处理

假设我们有一个getUserData(userId)函数,它返回有关用户的信息,或者如果参数出现问题则抛出错误userId

之前我们添加了正则try/catch并在catch块中处理错误。

try {
  console.log(getUserData(userId));
} catch (e) {
  handleError(e);
}
Enter fullscreen mode Exit fullscreen mode

但是,承诺中的异步代码中发生的错误无法通过常规方法捕获try/catch

让我们尝试用返回承诺的异步函数替换getUserData(userId)立即返回结果的同步函数。fetchUserData(userId)

我们希望保持相同的行为 - 如果成功则显示结果,如果发生错误则处理错误。

try {
  fetchUserData(userId).then(console.log);
} catch (e) {
  handleError(e);
}
Enter fullscreen mode Exit fullscreen mode

但我们不会成功。同步代码没有问题,所以执行会继续。但是,当异步代码中发生未处理的错误时,我们会收到一个错误UnhandledPromiseRejection,程序也会结束。

为了更好地理解程序的执行顺序,我们来添加一个finally块。它会一直运行(正如预期的那样),但它会在 之前还是之后运行呢UnhandledPromiseRejection

try {
  fetchUserData(userId).then(console.log);
} catch (e) {
  handleError(e);
} finally {
  console.log('finally');
}
Enter fullscreen mode Exit fullscreen mode

让我们一步一步尝试一下:

  1. try块中我们调用fetchUserData函数,该函数返回Promise状态pending
  2. catch块被忽略,因为块中没有错误try。异步执行尚未运行!
  3. finally行显示在屏幕上。
  4. 异步代码中发生错误,我们在控制台中看到错误消息 -UnhandledPromiseRejectionWarning

为了避免 Promises 中未处理的拒绝,您应该始终在 中处理它们.catch()

fetchUserData(userId).then(console.log).catch(handleError);
Enter fullscreen mode Exit fullscreen mode

代码变得更短、更干净,并且我们摆脱了破坏代码的意外错误。

这是一个关于处理 JavaScript 承诺链中的错误的有趣的编码面试问题

学习全栈 JavaScript

文章来源:https://dev.to/coderslang/javascript-asynchronous-programming-and-promises-1epl
PREV
Understanding map, filter, and zip in Python Understanding map, filter, and zip in Python
NEXT
Web 组件 101:原生 JavaScript