Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
当我们需要给予调用者一个承诺:待会儿我会给你回调数据时,就可以创建一个Promise的对象;

Promise的三个状态

  • 待定(pending: 初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled: 意味着操作成功完成。
  • 已拒绝(rejected: 意味着操作失败。

待定状态的 Promise 对象要么会通过一个值被兑现(fulfilled),要么会通过一个原因(错误)被拒绝(rejected)

Promise的基本结构

  1. function getData(param) {
  2. return new Promise((resolve, reject) => {
  3. setTimeout(() => {
  4. const b = true;
  5. if (b) {
  6. resolve("success");
  7. } else {
  8. reject("failed");
  9. }
  10. }, 1000);
  11. });
  12. }

executor

这是一个双参函数,参数为resolverejectPromise的实现会立即执行executor,并传入resolvereject函数。当resolvereject函数被调用时,它们分别对promise执行resolvereject
executor通常会触发一些异步运算,一旦运算成功完成,则resolve掉这个promise,如果出错则reject掉。如果executor函数执行时抛出异常,promise状态会变为rejectedexecutor的返回值也会被忽略。

resove函数调用时,不同值的区别

  • 如果resolve传入的是一个普通的值或者对象,那么这个值会作为then回调的参数。 ```javascript function getData(param) { return new Promise((resolve, reject) => { setTimeout(() => {
    1. resolve("success");
    }, 1000); }); }

getData().then((res) => { console.log(res); });

![image.png](https://cdn.nlark.com/yuque/0/2021/png/21450449/1638854335994-7097d7d0-c14f-4fe8-a29e-f968177db33c.png#clientId=u0b1380c5-3d0d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=121&id=u2d932ff1&margin=%5Bobject%20Object%5D&name=image.png&originHeight=121&originWidth=650&originalType=binary&ratio=1&rotation=0&showTitle=false&size=10129&status=done&style=none&taskId=u7b673881-c4e5-4b34-91b8-b9c585e2703&title=&width=650)

- 如果resolve传入的是另一个Promise对象,那么新的Promise对象会决定原Promise的状态。
```javascript
function getData(param) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const newPromise = new Promise((resolve, reject) => {
        setTimeout(() => {
          reject("newPromise failed");
        }, 2000);
      });
      resolve(newPromise);
    }, 1000);
  });
}

getData()
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log(err);
  });

image.png

  • 如果resolve传入的是一个对象,并且该对象中有then方法,那么会执行该then方法,并且根据then方法的结果来决定原Promise的状态。 ```javascript function getData(param) { return new Promise((resolve, reject) => { setTimeout(() => {
    const obj = {
      then(resolve, reject) {
        setTimeout(() => {
          reject("newPromise failed");
        }, 2000);
      },
    };
    resolve(obj);
    
    }, 1000); }); }

getData() .then((res) => { console.log(res); }) .catch((err) => { console.log(err); });

![image.png](https://cdn.nlark.com/yuque/0/2021/png/21450449/1638854456146-36fc4d56-556a-4e23-854f-3916ff5b59f4.png#clientId=u0b1380c5-3d0d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=110&id=FA8Ct&margin=%5Bobject%20Object%5D&name=image.png&originHeight=110&originWidth=647&originalType=binary&ratio=1&rotation=0&showTitle=false&size=10372&status=done&style=none&taskId=u551b65ea-f36e-431d-82d9-8d467839141&title=&width=647)
<a name="vGTNp"></a>
#### promise.then()
then方法是Promise对象上的一个方法:它其实是放在`Promise`的原型上的`Promise.prototype.then`。
:::info
then()方法返回一个Promise,它最多需要有两个参数:Promise 的成功和失败情况的回调函数。
:::
**语法:**
```javascript
p.then(onFulfilled[, onRejected]);

p.then(value => {
  // fulfillment
}, reason => {
  // rejection
});

返回值:
当一个 Promise 完成(fulfilled)或者失败(rejected)时,返回函数将被异步调用。具体的返回值依据以下规则返回。如果 then 中的回调函数:

  • 返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
  • 没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
  • 抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
  • 返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
  • 返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
  • 返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。

    promise.catch()

    catch方法是Promise对象上的一个方法:它其实是放在Promise的原型上的Promise.prototype.catch
    由于 then 和 Promise.prototype.catch() 方法都会返回 promise,它们可以被链式调用——这同时也是一种被称为复合( composition) 的操作。

    当一个promise未进行捕获(catch)操作,那么如果executor在执行过程中完成rejected时,会报错。 image.png

promise.finally()

finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象无论变成fulfilled还是reject状态,最终都会 被执行的代码。 :::info finally方法是不接收参数的,因为无论前面是fulfilled状态,还是reject状态,它都会执行。 :::

function getData(param) {
  return new Promise((resolve, reject) => {
    resolve();
  });
}

getData()
  .then((res) => {
    console.log(res);
  })
  .finally(() => {
    console.log("finally code");
  });

image.png

Promise的静态方法

Promise.resolve()

Promise.resolve(value)方法返回一个以给定值解析后的Promise对象。

Promise.resolve("suc").then((res) => {
  console.log(res);
});
// 等价于
new Promise((resolve) => {
  resolve("suc2");
}).then((res) => {
  console.log(res);
});

:::info Promise.resolve()方法的参数的三种情况与executorresolve函数调用时的区别一致。 :::

Promise.reject()

Promise.resolve()类似

Promise.all()

Promise.all()方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组

const p1 = new Promise((resolve) => {
  resolve("res1");
});

const p2 = new Promise((resolve) => {
  resolve("res2");
});

const p3 = new Promise((resolve) => {
  resolve("res3");
});

Promise.all([p1, p2, p3]).then((res) => {
  console.log(res);
});

image.png

Promise.allSetted()

Promise.all()方法有一个缺陷:当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态。那么对于resolved的,以及依然处于pending状态的Promise,我们是获取不到对应的结果的。

在ES11(ES2020)中,添加了新的API Promise.allSettled
**Promise.allSettled()**方法返回一个在所有给定的promise都已经fulfilledrejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。

const p1 = new Promise((resolve) => {
  resolve("res1");
});

const p2 = new Promise((resolve, reject) => {
  reject("res2");
});

const p3 = new Promise((resolve) => {
  resolve("res3");
});

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

image.png

Promise.race()

**Promise.race(iterable)** 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

Promise.any()

any方法是ES12中新增的方法。
**Promise.any()** 接收一个Promise可迭代对象,只要其中的一个 promise成功,就返回那个已经成功的 promise 。
如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError类型的实例,它是 Error 的一个子类,用于把单一的错误集合在一起。
本质上,这个方法和Promise.all()是相反的。 :::warning 注意! Promise.any() 方法依然是实验性的,尚未被所有的浏览器完全支持。 :::

手写Promise

1. Promise的基本实现

实现最简单的Promise以及基本调用流程
XPromise.js

const PROMISE_STATUS_PENDING = 0;
const PROMISE_STATUS_FULFILLED = 1;
const PROMISE_STATUS_REJECTED = 2;

class XPromise {
  constructor(executor) {
    // promise的状态
    this.status = PROMISE_STATUS_PENDING;
    this.onfulfilled = undefined
    this.onRejected = undefined

    // resolve函数
    this.resolve = (value) => {
      queueMicrotask(() => {
        if (this.status === PROMISE_STATUS_PENDING) {
          this.status = PROMISE_STATUS_FULFILLED;
          this.onfulfilled(value);
        }
      });
    };

    // reject函数
    this.reject = (reason) => {
      queueMicrotask(() => {
        if (this.status === PROMISE_STATUS_PENDING) {
          this.status = PROMISE_STATUS_REJECTED;
          this.onRejected(reason);
        }
      });
    };

    // 调用传入的函数,并将resolve和reject函数传入
    executor(this.resolve, this.reject);
  }

  // then方法
  then(onfulfilled) {
    this.onfulfilled = onfulfilled;
  }

  // catch方法
  catch(onRejected) {
    this.onRejected = onRejected;
  }
}

export { XPromise };

test.js

import { XPromise } from "./XPromise.js";

function getData() {
  return new XPromise((resolve, reject) => {
    setTimeout(() => {
      resolve("hello");
    }, 1000);
  });
}

getData().then((res) => {
  console.log(res);
});

2.(优化一)——多个then、catch的调用

XPromise.js

const PROMISE_STATUS_PENDING = 0;
const PROMISE_STATUS_FULFILLED = 1;
const PROMISE_STATUS_REJECTED = 2;

class XPromise {
  constructor(executor) {
    // promise的状态
    this.status = PROMISE_STATUS_PENDING;
    this.onfulfilledFns = [];
    this.onRejectedFns = [];

    // resolve函数
    this.resolve = (value) => {
      queueMicrotask(() => {
        if (this.status === PROMISE_STATUS_PENDING) {
          this.status = PROMISE_STATUS_FULFILLED;
          this.onfulfilledFns.forEach((fn) => {
            fn(value);
          });
        }
      });
    };

    // reject函数
    this.reject = (reason) => {
      queueMicrotask(() => {
        if (this.status === PROMISE_STATUS_PENDING) {
          this.status = PROMISE_STATUS_REJECTED;
          this.onRejectedFns.forEach((fn) => {
            fn(reason);
          });
        }
      });
    };

    // 调用传入的函数,并将resolve和reject函数传入
    executor(this.resolve, this.reject);
  }

  // then方法
  then(onfulfilled, onRejected) {
    if (onfulfilled) {
      this.onfulfilledFns.push(onfulfilled);
    }
    if (onRejected) {
      this.onRejectedFns.push(onRejected);
    }
  }

  // catch方法
  catch(onRejected) {
    if (onRejected) {
      this.onRejectedFns.push(onRejected);
    }
  }
}

export { XPromise };

test.js

import { XPromise } from "./XPromise.js";

function getData() {
  return new XPromise((resolve, reject) => {
    setTimeout(() => {
      resolve("hello");
    }, 1000);
  });
}

const p = getData();
p.then((res) => {
  console.log("then1", res);
});
p.then((res) => {
  console.log("then2", res);
});

p.catch((reason) => {
  console.log(reason);
});

3*.(优化二)——链式调用及异常处理

XPromise.js

const PROMISE_STATUS_PENDING = 0;
const PROMISE_STATUS_FULFILLED = 1;
const PROMISE_STATUS_REJECTED = 2;

/**
 * 生成一个携带resolve和reject的回调函数
 */
function generatorFn(callBack, resolve, reject) {
  return (value) => {
    try {
      const res = callBack(value);
      resolve(res);
    } catch (error) {
      reject(error);
    }
  };
}

class XPromise {
  constructor(executor) {
    // promise的状态
    this.status = PROMISE_STATUS_PENDING;
    this.onfulfilledFns = [];
    this.onRejectedFns = [];

    // resolve函数
    this.resolve = (value) => {
      queueMicrotask(() => {
        if (this.status === PROMISE_STATUS_PENDING) {
          this.status = PROMISE_STATUS_FULFILLED;
          this.onfulfilledFns.forEach((fn) => {
            fn(value);
          });
        }
      });
    };

    // reject函数
    this.reject = (reason) => {
      queueMicrotask(() => {
        if (this.status === PROMISE_STATUS_PENDING) {
          this.status = PROMISE_STATUS_REJECTED;
          this.onRejectedFns.forEach((fn) => {
            fn(reason);
          });
        }
      });
    };

    // 调用传入的函数,并将resolve和reject函数传入
    executor(this.resolve, this.reject);
  }

  // then方法
  then(onfulfilled, onRejected) {
    onfulfilled = onfulfilled ?? ((value) => value);

    // (重要)如果onRejected没有值,赋值为抛出异常,一直扔给下一个promise去处理
    const errFn = (err) => {
      throw err;
    };
    onRejected = onRejected ?? errFn;

    return new XPromise((resolve, reject) => {
      const fulfilledFn = generatorFn(onfulfilled, resolve, reject);
      this.onfulfilledFns.push(fulfilledFn);
      const rejectedFn = generatorFn(onRejected, resolve, reject);
      this.onRejectedFns.push(rejectedFn);
    });
  }

  // catch方法
  catch(onRejected) {
    return new XPromise((resolve, reject) => {
      if (onRejected) {
        const fn = generatorFn(onRejected, resolve, reject);
        this.onRejectedFns.push(fn);
      }
    });
  }
}

export { XPromise };

test.js

import { XPromise } from "./XPromise.js";

function getData() {
  return new XPromise((resolve, reject) => {
    setTimeout(() => {
      resolve("hello");
    }, 1000);
  });
}

const p = getData();
p.then((res) => {
  console.log("res1", res);
  throw new Error("test error");
  console.log("next code");
})
  .then((res) => {
    console.log("res2", res);
  })
  .then((res) => {
    console.log("res2", res);
  })
  .then((res) => {
    console.log("res2", res);
  })
  .catch((err) => {
    console.log(err);
  });

4.(优化三)——在Promise已经敲定状态下then()和catch()的处理

// ...
class XPromise {
  // ...

  // then方法
  then(onfulfilled, onRejected) {
    onfulfilled = onfulfilled ?? ((value) => value);

    // 如果onRejected没有值,赋值为抛出异常,一直扔给下一个promise去处理
    const errFn = (err) => {
      throw err;
    };
    onRejected = onRejected ?? errFn;

    return new XPromise((resolve, reject) => {
      // 判断该Promise的状态
      switch (this.status) {
        case PROMISE_STATUS_FULFILLED:
          // 直接执行
          generatorFn(onfulfilled, resolve, reject)(this.value);
          break;
        case PROMISE_STATUS_REJECTED:
          // 直接执行
          generatorFn(onRejected, resolve, reject)(this.reason);
          break;
        default:
          const fulfilledFn = generatorFn(onfulfilled, resolve, reject);
          this.onfulfilledFns.push(fulfilledFn);
          const rejectedFn = generatorFn(onRejected, resolve, reject);
          this.onRejectedFns.push(rejectedFn);
      }
    });
  }

  // catch方法
  catch(onRejected) {
    return new XPromise((resolve, reject) => {
      if (onRejected) {
        switch (this.status) {
          case PROMISE_STATUS_REJECTED:
            // 直接执行
            generatorFn(onRejected, resolve, reject)(this.reason);
            break;
          case PROMISE_STATUS_PENDING:
            const fn = generatorFn(onRejected, resolve, reject);
            this.onRejectedFns.push(fn);
        }
      }
    });
  }
}

export { XPromise };

5.(补充)finally方法的实现

直接调用then()

class XPromise {
  // ...
  finally(onFinally) {
  return this.then(
    () => {
      onFinally();
      return this.value;
    },
    () => {
      onFinally();
      throw this.reason;
    }
  );
}
}

6. (补充)Promise.resolve()及Promise.reject()

class XPromise {
  // ...
  static resolve(param) {
    return new XPromise((resolve, reject) => {
      resolve(param);
    });
  }
  static reject(reason) {
      return new XPromise((resolve, reject) => {
        reject(reason);
    })
  }
}

7.(补充)Promise.all()

class XPromise {
  // ...
  static all(xPromises) {
    return new XPromise((resolve, reject) => {
      const results = [];
      xPromises.forEach((p) => {
        p.then(
          (res) => {
            results.push(res);
            if (results.length === xPromises.length) {
              resolve(results);
            }
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }
}

8.(补充)Promise.allSetted()

class XPromise {
  // ...
    static allSetted(xPromises) {
    return new XPromise((resolve, reject) => {
      const results = [];
      xPromises.forEach((p) => {
        p.then(
          (res) => {
            results.push({
              status: "fulfilled",
              value: res,
            });
            if (results.length === xPromises.length) {
              resolve(results);
            }
          },
          (err) => {
            results.push({
              status: "rejected",
              reason: err,
            });
            if (results.length === xPromises.length) {
              resolve(results);
            }
          }
        );
      });
    });
  }
}

9.(补充)Promise.race()

class XPromise {
  // ...
static race(xPromises) {
    return new XPromise((resolve, reject) => {
      xPromises.forEach((p) => {
        p.then(
          (res) => resolve(res),
          (err) => reject(err)
        );
      });
    });
  }
}

10.(补充)Promise.any()

Promise.all()相反

class XPromise {
  // ...
  static all(xPromises) {
    return new XPromise((resolve, reject) => {
      const results = [];
      xPromises.forEach((p) => {
        p.then(
          (res) => {
            resolve(res)
          },
          (err) => {
            results.push(res);
            if (results.length === xPromises.length) {
              reject(results);
            }
          }
        );
      });
    });
  }
}