Promise 用法与实践

112 阅读4分钟

前言

JavaScript的异步编程模型是其最具挑战性的一部分,尤其对新手来说。JavaScript的Promise对象是一种处理异步操作的方法,它可以帮助我们更好地组织和管理异步代码。在这篇博客中,我们将深入探讨Promise的用法和实践。

什么是 Promise?

Promise是一个代表了某个未完成(或者说尚未决议)的异步操作的最终结果的对象。一个Promise有三种状态:

  • Pending(等待): 初始状态,不是fulfilled,也不是rejected。
  • Fulfilled(成功): 操作成功完成。
  • Rejected(失败): 操作失败。

Promise的状态一旦改变,就不会再变。Promise的主要优势在于,它允许我们以更易于理解和阅读的方式编写异步代码。

如何使用 Promise?

创建Promise是非常简单的,只需要使用new Promise()构造函数,如下所示:

let promise = new Promise((resolve, reject) => {
  // some code
});

在Promise的构造函数中,我们传入一个函数,这个函数接受两个参数:resolvereject,它们是两个函数,用来改变Promise的状态。

当异步操作成功时,我们调用resolve()函数,将Promise的状态改为fulfilled;当异步操作失败时,我们调用reject()函数,将Promise的状态改为rejected。

下面是一个实际的例子:

let promise = new Promise((resolve, reject) => {
  let isSuccessful = true; //模拟异步操作结果
  
  if(isSuccessful) {
    resolve('Operation is successful.');
  } else {
    reject(Error('Operation failed.'));
  }
});

Promise对象有两个方法:.then().catch(),分别用于处理fulfilled和rejected状态。

promise.then(message => {
  console.log(message); // 'Operation is successful.'
}).catch(error => {
  console.error(error); // 'Error: Operation failed.'
});

.then()方法接受一个函数作为参数,当Promise状态变为fulfilled时,这个函数会被调用,并接收到resolve()函数传入的值。.catch()方法也类似,不过它是处理Promise被rejected的情况。

此外,Promise还有一些静态方法,如Promise.all()Promise.race(),可以帮助我们更好地管理多个异步操作。

Promise.all

Promise.all()方法接受一个Promise对象的数组作为参数,返回一个新的Promise对象,当且仅当所有的Promise对象都变为fulfilled状态,这个新的Promise对象才会变为fulfilled状态。如果任何一个Promise对象变为rejected状态,那么新的Promise对象也会立即变为rejected状态。

let promise1 = Promise.resolve('Hello');
let promise2 = Promise.resolve('World');
let promise3 = Promise.resolve(123);

Promise.all([promise1, promise2, promise3])
  .then(values => {
    console.log(values); // ['Hello', 'World', 123]
  });

在这个例子中,Promise.all()接受了三个已经resolve的Promise对象,因此它返回的Promise对象的状态也是fulfilled,然后我们可以在.then()方法中访问这三个Promise的结果。

Promise.race

Promise.race()方法也接受一个Promise对象的数组作为参数,但它的行为与Promise.all()不同。Promise.race()返回一个新的Promise对象,这个新的Promise对象将会采用第一个改变状态的Promise对象的状态和值。

let promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

let promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2])
  .then(value => {
    console.log(value); // 'two'
  });

在这个例子中,promise2将会比promise1更早地改变状态,因此Promise.race()返回的Promise的值将会是’two’。

此外,ES2020还引入了 Promise.allSettled()Promise.any(),用于处理多个 Promise

Promise.allSettled

Promise.allSettled()方法接受一个Promise对象的数组作为参数,返回一个新的Promise对象。当所有的Promise对象都处于settled状态(无论fulfilled还是rejected),这个新的Promise对象才会变为fulfilled状态。

let promise1 = Promise.resolve(3);
let promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
let promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));

// "fulfilled"
// "rejected"

在这个例子中,无论promise1promise2的状态如何,Promise.allSettled()都会等待它们都完成。

Promise.any

Promise.any()方法接受一个Promise对象的数组作为参数,返回一个新的Promise。它和Promise.race()类似,但有一个关键区别:Promise.any()会等待所有的Promise对象都rejected后才会rejected,而Promise.race()则会在第一个Promise对象rejected后就rejected。

let promise1 = new Promise((resolve, reject) => setTimeout(reject, 500, 'one'));
let promise2 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'two'));
let promises = [promise1, promise2];

Promise.any(promises)
  .then((value) => console.log(value)) // "two"
  .catch((error) => console.log(error));

在这个例子中,Promise.any()返回的Promise对象的值是’two’,即使promise1promise2更早地变为rejected状态

以上的几种方法是我们可以更灵活的处理多个异步操作。

为什么使用 Promise?

Promise的主要优势是提供了一种更好的错误处理机制。使用.catch()方法,我们可以在Promise链的末尾处理所有的错误,而不是在每个异步操作后面都添加错误处理代码。

总的来说,理解和掌握Promise是成为一名高效JavaScript开发者的关键步骤。这些工具为处理复杂的异步操作提供了强大而灵活的方法。鼓励所有JavaScript开发者在项目中实践这些概念,以提高代码的可读性和维护性。