文章目录
多个期约组合在一起可以构成强大的代码逻辑。这种组合可以通
过两种方式实现:期约连锁与期约合成
一、Promise链
每个Promise方法都会返回一个新的Promise对象,新Promise又有自己的方法,这样就可以实现Promise链
let p = new Promise((resolve, reject) => {
console.log('first');
resolve();
});
p.then(() => console.log('second'))
.then(() => console.log('third'))
.then(() => console.log('fourth'));
// first
// second
// third
// fourth
实现了一串同步任务,但这并不是异步链,要真正执行异步任务,可以让每个执行器都返回一个期约实例,这样就可以让其他的处理程序(handler)将等待它 settled 后再获得其结果(result)
例:
let p = new Promise((resolve, reject) => {
console.log('1');
setTimeout(resolve, 1000);
});
p.then(() => new Promise((resolve, reject) => {
console.log('2');
setTimeout(resolve, 1000);
}))
.then(() => new Promise((resolve, reject) => {
console.log('3');
setTimeout(resolve, 1000);
}));
//1 (1秒后)
//2 (2秒后)
//3 (3秒后)
Promise链正好解决了回调地狱问题,且then()、catch()、finally()都返回Promise,可以同时串行
二、Promise合成
1. Promise.all()
这个静态方法接收一个可迭代对象(通常为数组),返回一个新期约
- 当所有给定的 promise 都被 settled 时,新的 promise 才会 resolve,并且其结果数组将成为新的 promise 的结果
let p = Promise.all([
new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
]);
console.log(p); // Promise <pending>
p.then(()=>{
console.log(p)}); // Promise <fulfilled> <value>:[1,2,3] 当上面这些 promise 准备好时:每个 promise 都贡献了数组中的一个元素
请注意,结果数组中元素的顺序与其在源 promise 中的顺序相同。即使第一个 promise 花费了最长的时间才 resolve,但它仍是结果数组中的第一个。(按迭代器顺序)
- 如果至少有一个包含的期约待定,则合成的期约也会待定。
let p1 = Promise.all([new Promise(() =>
{
})]);// 永远pending
let p2 = Promise.all([
Promise.resolve(),
Promise.reject(),
Promise.resolve()
]);
- 如果任意一个 promise 被 reject,由 Promise.all 返回的 promise 就会立即 reject,并且带有的就是这个 error
let p =Promise.all([
new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)),
new Promise((resolve, reject) => setTimeout(() => (console.log('test');reject(3)), 3000))
]).catch(alert); // Error: Whoops!
//test
第二个Promise被reject,拒绝的理由作为Promise.all拒绝的理由(Error:3)
之后再拒绝的Promise不会影响最终Promise.all的理由,但是会正常运行(输出test,静默处理reject(3) 不会有未处理的错误)
2. Promise.allSettled
如果任意的 promise reject,则 Promise.all 整个将会 reject。当我们需要 所有 结果都成功时,它对这种“全有或全无”的情况很有用:
Promise.all([
fetch('/template.html'),
fetch('/style.css'),
fetch('/data.json')
]).then(render); // render 方法需要所有 fetch 的数据
ps.该语言是ES2020新的内容,旧浏览器需要使用polyfill
3. Promise.race()
与 Promise.all 类似,但只等待第一个 settled 的 promise 并获取其结果(或 error)
// 解决先发生,超时后的拒绝被忽略
let p1 = Promise.race([
Promise.resolve(3),
new Promise((resolve, reject) =>
setTimeout(reject, 1000))
]);
setTimeout(console.log, 0, p1); // Promise <resolved>: 3
与Promise.all()类似,第一个settled之后的Promise还会正常执行,也会静默处理所有reject操作
三、Promise.resolve/reject
除了执行器函数进行settled还可以用以下两个静态方法进行settled:(用的不多)
1. Promise.resolve()
Promise.resolve(value) 用结果 value 创建一个 resolved 的 promise。
以下两个相等
let p1 = new Promise((resolve, reject) =>
resolve());
let p2 = Promise.resolve();
2. Promise.reject()
Promise.reject(error) 用 error 创建一个 rejected 的 promise。
四、Promise静态方法总结
Promise 类有 5 种静态方法:
- Promise.all(promises) —— 等待所有 promise 都 resolve 时,返回存放它们结果的数组。如果给定的任意一个 promise 为 reject,那么它就会变成 Promise.all 的 error,所有其他 promise 的结果都会被忽略。
- Promise.allSettled(promises)(ES2020 新增方法)—— 等待所有 promise 都 settle 时,并以包含以下内容的对象数组的形式返回它们的结果:
- status: “fulfilled” 或 “rejected”
- value(如果 fulfilled)或 reason(如果 rejected)。
- Promise.race(promises) —— 等待第一个 settle 的 promise,并将其 result/error 作为结果。
- Promise.resolve(value) —— 使用给定 value 创建一个 resolved 的 promise。
- Promise.reject(error) —— 使用给定 error 创建一个 rejected 的 promise。