(JavaScript) 对 Promise 的理解

114 阅读6分钟

形象的解释

理解 JavaScript 中的 Promise 就像理解一份订餐承诺。让我们通过一个比喻来详细解释:

设想你去一家餐馆吃晚餐,你点了一份特别的菜,而服务员告诉你这道菜需要一段时间才能做好,但你不必一直等着。这时,服务员会给你一张承诺单,上面写着"订餐承诺"。这张单上包含了以下信息:

  1. 状态(状态机):这个承诺单上有一个状态,可以是 "未完成"、"已完成" 或 "失败" 三种状态之一。一开始,它通常会是 "未完成",表示你的订单正在处理中。
  2. 值(结果):这个承诺单代表着你的订单,当菜做好时,这个订单就会包含你所期望的那份菜。
  3. 回调函数(then() 方法):这个承诺单上还有一个特殊的部分,它是一个回调函数,你可以告诉服务员当菜做好后应该做什么。比如,你可以告诉服务员,一旦这份特别的菜做好了,就把它送到你的桌子上。

现在,你可以回到你的桌子上坐下,等待你的食物。你不需要一直盯着厨房的门,而是可以坐下来做其他事情,因为你有那张订餐承诺单。服务员会在你的菜做好后,将菜送到你的桌子上,并且会根据你在承诺单上指定的回调函数,通知你菜已经准备好了。

这就是 Promise 在 JavaScript 中的作用:它允许你发起一个异步操作(点菜),然后得到一个承诺(订餐承诺单),可以在未来的某个时刻处理操作完成的结果。你可以在承诺上附加回调函数,以便在操作完成时执行特定的操作,就像在订餐承诺单上指定菜送到桌子上的操作一样。

此外,Promise 还有一些其他重要的特性,比如可以处理错误(拒绝承诺)和链式操作,这些也可以用类似的方式类比到餐馆的情境中。总之,Promise 是 JavaScript 中处理异步操作的强大工具,它使得编写更具可读性和可维护性的异步代码变得更加容易。

更加具体的解释

Promise 是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大。

所谓 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise 的实例的三个状态:

Pending(进行中)

Resolved(已完成)

Rejected(已拒绝)

当把一件事情交给 promise 时,它的状态就是 Pending,任务完成了状态就变成了 Resolved、没有完成失败了就变成了 Rejected。

Promise 的实例有两个过程:

pending -> fulfilled : Resolved(已完成)

pending -> rejected:Rejected(已拒绝)

注意:一旦从进行状态变成为其他状态就永远不能更改状态了。

Promise 的特点:

对象的状态不受外界影响。promise 对象代表一个异步操作,有三种状态,pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是 promise 这个名字的由来——“承诺”

一旦状态改变就不会再变,任何时候都可以得到这个结果。promise对象的状态改变,只有两种可能:从 pending 变为 fulfilled,从pending 变为 rejected。这时就称为 resolved(已定型)。如果改变已经发生了,你再对 promise 对象添加回调函数,也会立即得到这个结果。这与事件(event)完全不同,事件的特点是:如果你错过了它,再去监听是得不到结果的。

Promise 的缺点:

无法取消 Promise,一旦新建它就会立即执行,无法中途取消。如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始 还是即将完成)。

总结:

Promise 对象是异步编程的一种解决方案,最早由社区提出。Promise是一个构造函数,接收一个函数作为参数,返回一个 Promise 实例。一个 Promise 实例有三种状态,分别是 pending、resolved 和rejected,分别代表了进行中、已成功和已失败。实例的状态只能由pending 转变 resolved 或者 rejected 状态,并且状态一经改变,就凝固了,无法再被改变了。状态的改变是通过 resolve() 和 reject() 函数来实现的,可以在异步操作结束后调用这两个函数改变 Promise 实例的状态,它的原 型上定义了一个 then 方法,使用这个 then 方法可以为两个状态的改变注册回调函数。这个回调函数属于微任务,会在本轮事件循环的末尾执行。

注意:在构造 Promise 的时候,构造函数内部的代码是立即执行的

promise的用法

创建一个 Promise

你可以使用Promise构造函数来创建一个Promise对象,该构造函数接受一个带有两个参数的函数作为参数,这两个参数通常被称为resolvereject,它们用于在异步操作完成时决定Promise的状态。

const myPromise = new Promise((resolve, reject) => {
  // 异步操作,比如从服务器获取数据
  const success = true; // 假设异步操作成功
  if (success) {
    resolve("操作成功"); // 异步操作成功,将Promise状态改为fulfilled
  } else {
    reject("操作失败"); // 异步操作失败,将Promise状态改为rejected
  }
});

处理Promise状态

你可以使用.then()方法来处理Promise的状态,指定当Promise状态变为resolved(已完成)时应执行的回调函数和当Promise状态变为rejected(已拒绝)时应执行的回调函数。

myPromise
  .then((result) => {
    console.log("成功:", result); // 打印 "成功:操作成功"
  })
  .catch((error) => {
    console.error("失败:", error); // 打印 "失败:操作失败"
  });

Promise链式操作

一个Promise可以返回另一个Promise,这种机制可以创建Promise链,让多个异步操作按顺序执行。

const firstPromise = new Promise((resolve) => {
  setTimeout(() => {
    resolve("第一个Promise");
  }, 1000);
});

const secondPromise = firstPromise.then((result) => {
  console.log(result); // 打印 "第一个Promise"
  return "第二个Promise";
});

secondPromise.then((result) => {
  console.log(result); // 打印 "第二个Promise"
});

这个示例中,第一个Promise在1秒后解析,然后第二个Promise在第一个Promise解析后执行,并返回另一个值。