Skip to content

什么是 Promise

Published:

前言

Promise 这个东西有两层含义:一个是来自社区的 PromiseA+ 规范,另一个是 ES6 中的 Promise。虽然两者有联系,但也有一些区别。

PromiseA+ 规范

PromiseA+ 规范是一个由开发者社区提出的标准,目的是解决当时 JavaScript 异步操作中的一些问题,如“回调地狱”和缺乏一致的异步处理方式。它为如何实现一个标准的 Promise 提供了详细的指导。简单来说,PromiseA+ 规范是异步编程的一套协议,它规定了 Promise 对象必须具有的行为和功能。

在这个规范中,Promise 是一个“带有 then 方法的东西”。这个“东西”可以是对象,也可以是函数。关键是它必须具备 then 方法,这个方法能够接受两个参数,一个用于处理成功的回调,另一个用于处理失败的回调。

// 符合 Promise A+ 规范的结构
{
  then(onFulfilled, onRejected) {
    // 实现细节
  }
  then(onFulfilled, onRejected) {
    // ....
  }
}

function A() {}
A.then = function(onFulfilled, onRejected) {
  // 实现细节
}
A.then .....
A.then .....

then 方法是 PromiseA+ 规范的核心。它负责处理异步操作完成后的逻辑,并返回一个新的 Promise,使得 Promise 可以链式调用。这种设计使得我们能够避免嵌套的回调,从而解决了“回调地狱”问题。

ES6 的 Promise

在 ES6 规范中,加入了原生的 Promise 支持。通过一个构造函数 Promise 去做一些事情。通过构造函数创建出来的实例,满足了PromiseA+规范。也可以称之为 PromiseA+ 规范的实现。

简单粗暴地理解为:PromiseA+ 社区提供了一个蓝本,一份草稿,然后 ES6 的Promise构造函数就将这份规范给实现了。

所以,我们可以看到,只要我们 new 了一个 Promise,那么这个实例化对象就带有 then 方法。

const _promise = new Promise((res, rej) => console.log(res));
// 这里实例化后的 _promise 带有原型链上的 then 方法
_promise.then;

除此之外,ES6 对 PromiseA+ 规范进行了扩展,除了 then 方法外,还有 catchfinally 等。

catch 方法catch 用来捕获 Promise 中的错误。它是 then 的一个简化版,用来处理失败的情况。

var p = new Promise((resolve, reject) => {
  // 这里是一些异步操作
  reject("出错了"); // 比如说操作失败了
});

p.catch(error => {
  console.log(error); // 这里会输出 "出错了"
});

finally 方法finally 是无论 Promise 成功还是失败,都会执行的一段代码。它通常用来做一些清理工作,比如关闭网络连接、隐藏加载动画等。

p.finally(() => {
  console.log("操作结束,无论成功或失败都会执行");
});

Promise.all()Promise.all() 接受一个 Promise 数组,当所有的 Promise 都成功时,返回一个新的 Promise,这个 Promise 的值是所有 Promise 结果的数组。如果有一个 Promise 失败,那么返回的 Promise 也会立即失败。

Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log(results); // 输出所有 Promise 的结果
  })
  .catch(error => {
    console.error(error); // 输出第一个失败的原因
  });

Promise.race()Promise.race() 也是接受一个 Promise 数组,只不过它是哪个 Promise 先完成就返回哪个的结果。如果第一个完成的是失败的,那么整个 Promise.race() 就失败。

Promise.race([promise1, promise2, promise3])
  .then(result => {
    console.log(result); // 输出第一个完成的 Promise 结果
  })
  .catch(error => {
    console.error(error); // 输出第一个失败的原因
  });