关于 Promise 的易错理解及四种静态方法 all allSettled race any 的实现方法。
Promise 的理解
- Promise 总共有三种状态,分别是 Pending Fulfilled Rejected 三种状态,状态流转只能是单向的,只能由 Pending–>Fulfilled 或者 Pending–>Rejected.
- Promise 实例化对象上的 then 只是取出 Promise 的值而已,并不是执行 Promise,Promise 执行的时候是在实例化对象的时候就已经进行了。
- Promise 实例化的对象上 then 方法 return 的值会自动被 Promise 包裹,因此 Promise 会形成链式调用。
- catch 方法实际上是 Promise 实例对象上的第二个参数(错误捕获的回调函数)的语法糖。
- all allSettled race any 都是 Promise 这个类的静态方法只能由
Promise.all
这样调用,不是在实例化的对象上调用。
all 方法
- 作用:接收一组值,用数组存储,返回一个 Promise 对象,当 Promise 中没有 reject 的值时,将所有 promise resolve 的值存储到数组里,通过 then 的第一个回调取出。只要出现 reject 就立刻 catch
- 注意事项:
- 接收的值可以是 Promise 也可以不是 Promise,函数会自动将非 Promise 的值转化为 Promise。
- 所有 Promise 都执行了,then 方法只是进行了取值操作
- 实现注意细节
- 必须对入参进行数组校验
- 入参可以不是 Promise 但要对非 Promise 的值进行包裹成为 Promise
- 输出的结果的顺序得和入参的顺序保持一致
- 测试时候建议将 ts 注释删除使用 js 在浏览器内测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| function promiseAll(arr: any[]): Promise<any> { return new Promise((resolve, reject) => { if (!Array.isArray(arr)) reject(new Error("传参必须是数组")); const values: any[] = []; let counter = 0; arr.forEach((promise, index) => { Promise.resolve(promise) .then((res) => { values[index] = res; counter++; if (counter === arr.length) resolve(values); }) .catch((err) => { reject(err); }); }); }); }
const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve(1000); }, 1000); }); const p2 = new Promise((resolve, reject) => { setTimeout(() => { reject("err:2000"); }, 2000); });
const p3 = new Promise((resolve, reject) => { setTimeout(() => { console.log("前面失败了但是promise依然执行"); resolve(3000); }, 3000); }); const p4 = "非Promise值"; promiseAll([p3, p4, p1]) .then((res) => { console.log("res:", res); }) .catch((err) => { console.log(err); });
|
allSettled 方法
allSettled 是为了解决 all 方法的缺陷产生的,主要解决的是不论是否 reject 都把对应的值存起来,因此它没有 catch 方法。
同样的注意事项与 all 相同的不在赘述,只是 allSettled 特别的需要注意没有 reject,因为所有的 promise 值都分为状态保存都 resolve 出去了。还有一点就是Promise.allSettled 不会捕获 throw new Error 的错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| function promiseAllSettled(arr: any[]): Promise<any> { return new Promise((resolve, reject) => { if (!Array.isArray(arr)) reject(new Error("传参必须是数组")); const values: any[] = []; let counter = 0; arr.forEach((promise, index) => { Promise.resolve(promise) .then((res) => { values[index] = { status: "fulfilled", value: res }; counter++; if (counter === arr.length) resolve(values); }) .catch((err) => { values[index] = { status: "rejected", reason: err }; counter++; if (counter === arr.length) resolve(values); }); }); }); }
|
race 方法
race 是竞速的意思,最快的 promise 解决或者拒绝的时候 Promise.all 的 promise 就解决或者拒绝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function promiseRace(arr: any[]): Promise<any> { return new Promise((resolve, reject) => { if (!Array.isArray(arr)) reject(new Error("传参必须是数组")); arr.forEach((promise) => { Promise.resolve(promise) .then((res) => {
resolve(res); }) .catch((err) => { reject(err); }); }); }); }
|
any 方法
any 是为了解决 race 的缺陷,当第一个 promise 解决的时候才 resolve。不论前面是否有 promise 拒绝,只有当所有 promise 都拒绝,才 rejecte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function promiseAny(arr: any[]): Promise<any> { return new Promise((resolve, reject) => { if (!Array.isArray(arr)) reject(new Error("传参必须是数组")); const reasons: any[] = []; let counter = 0; arr.forEach((promise, index) => { Promise.resolve(promise) .then((res) => { resolve(res); }) .catch((err) => { counter++; reasons[index] = err; if (counter === arr.length) reject(new AggregateError(reasons)); }); }); }); }
|