话说Promise这些注意事项你都清楚了吗

28 阅读3分钟

Promise 对象

p1 的状态会传递给 p2 (p2 状态无效)

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error("fail")), 3000);
});

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000);
});

p2.then((result) => console.log("【res】", result))
.catch((error) => console.log("【err】", error));
// 【err】Error: fail

调用resolvereject并不会终结 Promise 的参数函数的执行

new Promise((resolve, reject) => {
  console.log(0);
  resolve(1);
  console.log(2); // 依旧执行
}).then((r) => {
  console.log(r);
});
console.log(3);
// 0
// 2
// 3
// 1

Promise 状态已经变成 resolved,再抛出错误是无效的

const promise = new Promise(function (resolve, reject) {
  resolve("ok");
  throw new Error("test");
});
promise
  .then(function (value) {
    console.log(value);
  })
  .catch(function (error) {
    console.log(error);
  });
// ok

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。(中间的 then 代码不会执行)

new Promise((resolve, reject) => {
  console.log(1);
  reject("Error1");
})
  .then((res) => {
    conso.log(2);
    conso.log(res);
  })
  .catch((err) => {
    console.log(3);
    console.log(err);
  });

// 1
// 3
// Error1

Promise 对象抛出的错误不会传递到外层代码,“Promise 会吃掉错误”

new Promise((resolve, reject) => {
  console.log(1);
  // 下面一行会报错,因为x没有声明
  resolve(x + "test");
  console.log(2);
})
  .then(() => {
    console.log(3);
  })
  .catch((err) => {
    console.log(err);
  });

console.log('main')

// 1
// main
// ReferenceError: x is not defined

Promise.all 和 Promise.allSettled

Promise.all

Promise.all()方法接受一个数组作为参数,如果数组某一项不是 Promise 实例,会使用 Promise.resolve()将其转为 Promise 实例。

当数组每一项的状态都变成 fulfilled,p 状态才会 fulfilled。只要有一项状态变成 rejected,p 就变成 rejected。

const p = Promise.all([p1, p2, p3]);

注意,数组项的 Promise 实例,自己定义了 catch 方法,那么它一旦被 rejected,并不会触发 Promise.all()的 catch 方法。

const p1 = new Promise((resolve, reject) => {
  resolve("hello");
}).catch((e) => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error("报错了");
}).catch((e) => e);

Promise.all([p1, p2])
  .then((result) => console.log("success", result))
  .catch((e) => console.log("error", e));

// success (2) ['hello', Error: 报错了...]
// 可以看到走的是then,而不是catch

Promise.allSettled

只有等到参数数组的所有 Promise 对象都发生状态变更(不管是 fulfilled 还是 rejected),返回的 Promise 对象才会发生状态变更。

该方法返回的新的 Promise 实例,一旦发生状态变更,状态总是 fulfilled,不会变成 rejected。

Promise.any

接受数组作为参数。只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态。

Promise.any([
  fetch("https://v8.dev/").then(() => "home"),
  fetch("https://v8.dev/blog").then(() => "blog"),
  fetch("https://v8.dev/docs").then(() => "docs"),
])
  .then((first) => {
    // 只要有一个 fetch() 请求成功
    console.log(first);
  })
  .catch((error) => {
    // 所有三个 fetch() 全部请求失败
    console.log(error);
  });

Promise.resolve

参数是一个 Promise 实例

如果参数是 Promise 实例,那么 Promise.resolve 将不做任何修改、原封不动地返回这个实例。(就是说如果传入的是 rejected 状态的实例,那么后续依旧是 rejected)

参数是一个 thenable 对象

Promise.resolve()方法会将这个对象转为 Promise 对象,然后就立即执行 thenable 对象的 then()方法。

let thenable = {
  then: function (resolve, reject) {
    console.log(1)
    resolve(42);
  },
};

let p1 = Promise.resolve(thenable);
p1.then(function (value) {
  console.log(value);
});
console.log(2)

// 2
// 1
// 42

参数不是具有 then()方法的对象,或根本就不是对象

如果参数是一个原始值,或者是一个不具有 then()方法的对象,则 Promise.resolve()方法返回一个新的 Promise 对象,状态为 resolved。

不带有任何参数

直接返回一个 resolved 状态的 Promise 对象。

Promise.reject

Promise.reject()方法的参数,会原封不动地作为 reject 的理由,变成后续方法的参数。(就是它不会像 Promise.resolve 那样处理参数)

参考资料

es6.ruanyifeng.com/#docs/promi…