跳转至

JavaScript 异步编程:Promise

概述

在 JavaScript 中,异步编程是处理耗时操作(如网络请求、文件读写等)的关键。传统的回调函数虽然可以实现异步操作,但随着代码复杂度的增加,回调地狱(Callback Hell)问题变得难以管理。为了解决这个问题,ES6 引入了 Promise,它提供了一种更优雅的方式来处理异步操作。

什么是 Promise?

Promise 是一个表示异步操作最终完成或失败的对象。它有三种状态:

  1. Pending(进行中):初始状态,既不是成功,也不是失败。
  2. Fulfilled(已成功):操作成功完成。
  3. Rejected(已失败):操作失败。

Promise 的状态一旦改变,就不会再变。这意味着一个 Promise 只能从 Pending 变为 FulfilledRejected,且不可逆。

创建 Promise

你可以使用 new Promise() 构造函数来创建一个 Promise 对象。构造函数接受一个函数作为参数,这个函数有两个参数:resolvereject,它们分别是成功和失败时的回调函数。

const myPromise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const success = true; // 模拟操作成功或失败
    if (success) {
      resolve("操作成功!");
    } else {
      reject("操作失败!");
    }
  }, 1000);
});

在上面的代码中,setTimeout 模拟了一个异步操作。如果操作成功,调用 resolve 并传递结果;如果失败,调用 reject 并传递错误信息。

处理 Promise

使用 .then().catch()

Promise 提供了 .then().catch() 方法来处理成功和失败的情况。

myPromise
  .then((result) => {
    console.log(result); // 输出: 操作成功!
  })
  .catch((error) => {
    console.error(error); // 输出: 操作失败!
  });
  • .then() 方法接收一个回调函数,当 Promise 状态变为 Fulfilled 时调用。
  • .catch() 方法接收一个回调函数,当 Promise 状态变为 Rejected 时调用。

使用 .finally()

.finally() 方法无论 Promise 成功还是失败都会执行,通常用于清理操作。

myPromise
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.error(error);
  })
  .finally(() => {
    console.log("操作完成!");
  });

链式调用

Promise 支持链式调用,这意味着你可以在一个 .then() 中返回一个新的 Promise,并在下一个 .then() 中处理它。

const fetchData = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("数据获取成功!");
    }, 1000);
  });
};

fetchData()
  .then((data) => {
    console.log(data); // 输出: 数据获取成功!
    return "处理数据...";
  })
  .then((processedData) => {
    console.log(processedData); // 输出: 处理数据...
  })
  .catch((error) => {
    console.error(error);
  });

并行处理多个 Promise

你可以使用 Promise.all() 方法来并行处理多个 Promise,并在所有 Promise 都成功时返回结果数组。

const promise1 = Promise.resolve("第一个操作成功!");
const promise2 = new Promise((resolve) => {
  setTimeout(() => {
    resolve("第二个操作成功!");
  }, 1000);
});

Promise.all([promise1, promise2])
  .then((results) => {
    console.log(results); // 输出: ["第一个操作成功!", "第二个操作成功!"]
  })
  .catch((error) => {
    console.error(error);
  });

如果其中一个 Promise 失败,Promise.all() 会立即返回失败的结果。

练习题

练习 1:基本 Promise 使用

编写一个 Promise,模拟一个异步操作,操作成功时返回 "Hello, World!",失败时返回 "Error!"。使用 .then().catch() 处理结果。

练习 2:链式调用

编写一个 Promise 链,模拟以下操作: 1. 获取用户数据(模拟异步操作,返回 "用户数据获取成功!")。 2. 处理用户数据(返回 "用户数据处理完成!")。 3. 保存用户数据(返回 "用户数据保存成功!")。

练习 3:并行处理

编写三个 Promise,分别模拟三个异步操作,每个操作耗时不同(1秒、2秒、3秒)。使用 Promise.all() 并行处理这三个 Promise,并在所有操作完成后输出结果。

总结

  • Promise 是 JavaScript 中处理异步操作的一种方式,它有三种状态:PendingFulfilledRejected
  • 使用 .then() 处理成功的结果,使用 .catch() 处理失败的结果,使用 .finally() 执行清理操作。
  • Promise 支持链式调用,可以在一个 .then() 中返回新的 Promise
  • 使用 Promise.all() 可以并行处理多个 Promise,并在所有 Promise 都成功时返回结果数组。

通过掌握 Promise,你可以更优雅地处理 JavaScript 中的异步操作,避免回调地狱,并编写出更清晰、更易维护的代码。