学习 JavaScript Promises 什么是 Promises?为什么要使用 Promises?处理多个 Promises

2025-06-07

学习 JavaScript Promises

什么是承诺?

为什么要承诺?

处理多个承诺

大家好,我将简要介绍一下 JavaScript 的 Promise 以及它们的工作原理。Promise 已经存在一段时间了。由于现代开发都围绕异步代码进行,理解这个概念至关重要。我们先来定义一下 Promise 是什么:

什么是承诺?

在 JavaScript 中,Promise 是一个返回某种类型的值的对象,该值将在未来的任何时候到达。在此过程中,Promise 会以 pending 状态启动,这表示它尚未完成,并且最终会返回一个值。在被使用后,此返回值可以处于已解决状态(成功)或已拒绝状态(失败)。

理解 Promise 的三个主要状态非常重要。

  • 待处理: Promise 仍在执行其工作,我们尚不知道响应的类型。我们只知道我们被承诺了一个值。
  • 已解决:承诺的价值已成功交付。
  • 被拒绝:承诺的价值尚未成功交付,我们收到了被拒绝的原因的解释。

现在让我们将这些信息付诸实践。

让我们创建一个 Promise

让我们从一个简单的例子开始。在下图中,我们立即创建并消费了一个 Promise。

const isPromisedFullfilled = true;

const myPromise = () => {
  return new Promise((resolve, reject) => {
    if (isPromisedFullfilled) {
      resolve("Hello, this is a successful Promise");
    }
    reject("Hello, this is a rejected Promise");
  });
};

console.log(myPromise()); // Promise {<pending>}

myPromise()
  .then((result) => console.log(`Success: ${result}`)) // if true = resolved
  .catch((err) => console.log(`Error: ${err}`)); // if false = rejected

// Output: Success: Hello, this is a successful Promise
Enter fullscreen mode Exit fullscreen mode

现在让我们分解一下上面示例的每个部分。一个名为 的函数myPromise返回一个 Promise。在myPromise函数内部,我们可以访问参数的resolvereject方法。这些方法允许您解析或拒绝一个值。一旦 Promise 被消费,这将定义该 Promise 是否已实现。在本例中,我们有一个名为 的变量isPromisedFullfilled,它具有布尔值,当 Promise 被消费时,它将根据变量值解析或拒绝。

如果isPromisedFullfilledequals 为 true,它将返回一条消息“Hello, this is a successful Promise”。如果 equals 为 false,它将运行下一行代码,该代码将拒绝该 Promise 并返回一条消息“Hello, this is a accepted Promise”。这将在 Promise 被消费后发生。

const isPromisedFullfilled = true;

const myPromise = () => {
  return new Promise((resolve, reject) => {
    if (isPromisedFullfilled) {
      resolve("Hello, this is a successful Promise");
    }
    reject("Hello, this is a rejected Promise");
  });
};
Enter fullscreen mode Exit fullscreen mode

myPromise在创建状态下,我们登录控制台可以看到Promise仍然处于待处理状态。

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

让我们处理 Promise

为了使用 Promise,我们需要访问一个.then()接受两个回调函数的方法——一个用于 Promise 的成功情况,一个用于 Promise 失败的情况。然而,通常情况下,Promise 的失败情况由.catch()一个只接受一个回调函数的方法处理,该方法用于处理被拒绝的状态或抛出的错误。

如下所示,.then()该方法将处理已解决状态并提供结果,并将.catch()处理已拒绝状态并提供错误原因。在本例中,isPromisedFullfilledequals 为 true,因此结果将是“Success: Hello, this is a successful promise”。

myPromise()
  .then((result) => console.log(`Success: ${result}`)) // if true = resolved
  .catch((err) => console.log(`Error: ${err}`)); // if false = rejected

// Output: Success: Hello, this is a successful Promise
Enter fullscreen mode Exit fullscreen mode

为什么要承诺?

Promises 的设计初衷是为了更轻松地处理异步操作,并解决函数嵌套函数时出现的“回调地狱”。我们通常在处理异步编程时会看到这种模式,但随着 Promises 的引入,我们只需要一个.then()接一个地添加即可。如果我们将上面的例子转换为“回调”,它看起来会像这样:

let done = false;

function doSomething(successCallback, errorCallback) {
  if (done) {
    successCallback("Hello, this is a successful result");
  } else {
    errorCallback("Hello, this is a failed result");
  }
}

doSomething(
  (result) => console.log(`Success: ${result}`),
  (err) => console.log(`Error: ${err}`)
);
Enter fullscreen mode Exit fullscreen mode

尽管几个回调似乎不是什么大问题,但是一旦我们开始嵌套它们,使用回调很快就会失控。

现在我们知道 Promises 解决了一些问题,但归根结底,这并不是使用 Promises 时出现的其他问题的最终解决方案,但理解它们对于继续使用处理异步代码(如 Async/Await)的其他方式非常重要。

处理多个承诺

有一些重要的静态方法可以帮助我们针对不同情况同时处理多个 Promise,它们是:

  1. Promise.all()
  2. Promise.allSettled()
  3. Promise.race()
  4. Promise.any()

我将对每一个进行简要的解释。

Promise.all()

此方法接受一个 Promise 数组作为参数,并等待所有 Promise 都解析完毕。解析完毕后,它将返回一个 Promise,我们可以通过一个方法访问一个包含所有已解析 Promise 结果的数组.then()

const p1 = new Promise((resolve, reject) => {
  resolve("This is the first Promise"); // resolves
});

const p2 = new Promise((resolve, reject) => {
  resolve("This is the second Promise"); // resolves
});

Promise.all([p1, p2])
  .then((result) => console.log(result))
  .catch((err) => console.log(err));

// Output: 
// ["This is the first Promise", "This is the second Promise"]
Enter fullscreen mode Exit fullscreen mode

如果其中一个 Promise 被拒绝,则仅返回第一个被拒绝的 Promise 的原因。如下所示。

const p1 = new Promise((resolve, reject) => {
  resolve("This is the first Promise"); // resolves
});

const p2 = new Promise((resolve, reject) => {
  reject("This is the second Promise"); // rejects
});

const p3 = new Promise((resolve, reject) => {
  reject("This is the third Promise"); // rejects
});

Promise.all([p1, p2, p3])
  .then((result) => console.log(result))
  .catch((err) => console.log(err));

// Output: "This is the second Promise"
Enter fullscreen mode Exit fullscreen mode

Promise.allSettled()

此方法与 类似Promise.all()。它也接受一个 Promise 数组作为参数,但不同之处在于,它会在所有 Promise 均已解决或拒绝后返回一个已解决的 Promise。使用 处理返回的 Promise 后.then(),我们可以访问一个包含每个 Promise 信息的对象数组。

const p1 = new Promise((resolve, reject) => {
  resolve("This is the first Promise"); // resolves
});

const p2 = new Promise((resolve, reject) => {
  reject("This is the second Promise"); // rejects
});

const p3 = new Promise((resolve, reject) => {
  reject("This is the third Promise"); // rejects
});

Promise.allSettled([p1, p2, p3])
  .then((results) => console.log(results));

// Output: [Object, Object, Object]
Enter fullscreen mode Exit fullscreen mode

如上例所示,我们得到了一个对象数组。循环遍历结果并将结果打印到控制台后,我们可以看到每个 Promise 对象中包含的有用信息。

Promise.allSettled([p1, p2, p3])
  .then((results) => {
    results.forEach((result) => {
      console.log(result)
    })
  })

// Output: 
// {status: "fulfilled", value: "This is the first Promise"}
// {status: "rejected", reason: "This is the second Promise"}
// {status: "rejected", reason: "This is the third Promise"}
Enter fullscreen mode Exit fullscreen mode

Promise.race()

此方法接受一个 Promise 数组,并在任何 Promise 解析或拒绝后立即返回已完成的 Promise。在下面的示例中,第三个 Promise 在第二个 Promise 解析后解析,因此其结果将在 上处理.then();如果第一个 Promise 被拒绝,则错误将在 上处理.catch()

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("This is the first Promise"), 3000); 
  // resolves after 3 seconds 
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => reject("This is the second Promise"), 2000); 
  // rejects after 2 seconds 
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("This is the third Promise"), 1000); 
  // resolves after 1 second
});

// Promise.race()
Promise.race([p1, p2, p3])
  .then((result) => console.log(result))
  .catch((err) => console.log(err));

// Output: "This is the third Promise"
Enter fullscreen mode Exit fullscreen mode

Promise.any()

此方法基本上与相反Promise.all()Promise.any()如果所有承诺都被拒绝,它将返回AggregateError如下所示的。

const p1 = new Promise((resolve, reject) => {
  reject("This is the first Promise"); // rejects
});

const p2 = new Promise((resolve, reject) => {
  reject("This is the second Promise"); // rejects
});

Promise.any([p1, p2])
  .then((result) => console.log(result))
  .catch((err) => console.log("Error: " + err));

// Output: "Error: AggregateError: All promises were rejected"
Enter fullscreen mode Exit fullscreen mode

当 Promise 解析后,它将返回一个 Promise,其解析值来自最快完成的 Promise。在下面的示例中,仅用一秒钟解析的 Promise 将是该.then()方法中已处理 Promise 的结果。

const p1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 2000, "This is the first Promise"); 
  // resolves after 2 seconds
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, "This is the second Promise"); 
  // resolves after 1 second
});

Promise.any([p1, p2])
  .then((result) => console.log(result))
  .catch((err) => console.log(err));

// Output: "This is the second Promise"
Enter fullscreen mode Exit fullscreen mode

Promises 是 JavaScript 中一个非常有趣的部分,因为它提供了各种处理异步任务的功能。尽管在新版本的 JavaScript 中,有更好的方法来处理异步编程,但理解 Promises 的工作原理仍然非常重要。

今天就到这里!提醒一下,本指南基于我对 Promise 的学习以及我的理解。请务必留下你的反馈,告诉我哪些地方可以改进,希望它也能对正在学习 Promise 的朋友们有所帮助。再见!下期再见!!!😃

文章来源:https://dev.to/marlonry/learning-javascript-promises-2dep
PREV
将 React 代码库迁移到 Web 组件
NEXT
如何使用 Solidity 和 Hardhat 编写 ERC20 代币预售智能合约