promise静态方法

关于 Promise 的易错理解及四种静态方法 all allSettled race any 的实现方法。

Promise 的理解

  1. Promise 总共有三种状态,分别是 Pending Fulfilled Rejected 三种状态,状态流转只能是单向的,只能由 Pending–>Fulfilled 或者 Pending–>Rejected.
  2. Promise 实例化对象上的 then 只是取出 Promise 的值而已,并不是执行 Promise,Promise 执行的时候是在实例化对象的时候就已经进行了。
  3. Promise 实例化的对象上 then 方法 return 的值会自动被 Promise 包裹,因此 Promise 会形成链式调用。
  4. catch 方法实际上是 Promise 实例对象上的第二个参数(错误捕获的回调函数)的语法糖。
  5. all allSettled race any 都是 Promise 这个类的静态方法只能由Promise.all这样调用,不是在实例化的对象上调用。

all 方法

  1. 作用:接收一组值,用数组存储,返回一个 Promise 对象,当 Promise 中没有 reject 的值时,将所有 promise resolve 的值存储到数组里,通过 then 的第一个回调取出。只要出现 reject 就立刻 catch
  2. 注意事项:
    • 接收的值可以是 Promise 也可以不是 Promise,函数会自动将非 Promise 的值转化为 Promise。
    • 所有 Promise 都执行了,then 方法只是进行了取值操作
  3. 实现注意细节
    • 必须对入参进行数组校验
    • 入参可以不是 Promise 但要对非 Promise 的值进行包裹成为 Promise
    • 输出的结果的顺序得和入参的顺序保持一致
  4. 测试时候建议将 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 但得经过Promise包装
Promise.resolve(promise)
.then((res) => {
// 数组输出的结果和入参的Promise顺序得一致
values[index] = res;
counter++;
//只有所有的Promise都resolve了之后才返回值
if (counter === arr.length) resolve(values);
})
.catch((err) => {
// 一个Promise出错了reject
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);
});

/* promiseAll([p3, p2, 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 但得经过Promise包装
Promise.resolve(promise)
.then((res) => {
// 数组输出的结果和入参的Promise顺序得一致
values[index] = { status: "fulfilled", value: res };
counter++;
//所有Promise执行完成后 才resolve
if (counter === arr.length) resolve(values);
})
.catch((err) => {
values[index] = { status: "rejected", reason: err };
counter++;
//所有Promise执行完成后 才resolve 没有catch捕获错误
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 但得经过Promise包装
Promise.resolve(promise)
.then((res) => {
// 数组输出的结果和入参的Promise顺序得一致

//所有Promise执行完成后 才resolve
resolve(res);
})
.catch((err) => {
//所有Promise执行完成后 才resolve 没有catch捕获错误
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 但得经过Promise包装
Promise.resolve(promise)
.then((res) => {
//一旦有promise解决就resolve
resolve(res);
})
.catch((err) => {
counter++;
reasons[index] = err;
//所有Promise都reject 才reject
if (counter === arr.length) reject(new AggregateError(reasons));
});
});
});
}

promise静态方法
https://sunburst89757.github.io/2022/09/25/promise/
作者
Sunburst89757
发布于
2022年9月25日
许可协议