这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」。
期约连锁与期约合成
期约连锁就是一个期约接一个期约地拼接,期约合成是将多个期约组合为一个期约。
期约连锁
在前面有讲过,Promise的实例方法,如then()、catch()、finally()这些实例方法都会返回一个新的Promise对象,而这个新的Promise对象又有自己的实例方法,就这样可以实现把Promise逐个串联起来。
Promise解决 回调地狱 的问题就用了这一特性
// 回调地狱,回调函数深入嵌套
function fn(str, cb=null) {
setTimeout(()=> {
console.log(str);
cb && cb()
},1000)
}
fn('p1', () => {
fn('p2', () => {
fn('p3', () => {
})
})
})
// p1 (1s后)
// p2 (2s后)
// p3 (3s后)
// Promise
let p1 = new Promise((resolve, reject) => {
console.log('p1');
setTimeout(resolve, 1000);
})
p1.then(() => new Promise((resolve, reject) => {
console.log('p2')
setTimeout(resolve, 1000)
})).then(() => new Promise((resolve, reject) => {
console.log('p3')
setTimeout(resolve, 1000)
}))
// p1
// p2 (1s后)
// p3 (2s后)
期约合成
Promise 类提供两个将多个期约实例组合成一个期约的静态方法:Promise.all()和 Promise.race()。
Promise.all()
这个静态方法创建的期约会在一组期约全部解决之后再解决。它接收一组可迭代的对象。
let p = Promise.all([
Promise.resolve(1),
Promise.resolve(2)
])
// p Promise {<fulfilled>: Array(2)}
p.then((e) => {
console.log(e) // [1, 2]
})
传入不同的参数情况:
- 如果不传参数呢?或不可迭代?
let p = Promise.all();
报错了
- 如果迭代对象中的元素不是Promise对象呢?
let p1 = Promise.all([1,2,3])
let p2 = Promise.all([]);
可迭代对象的元素被Promise.resolve()转换成了期约
- 如果包含待定的或拒绝的呢?
let p1 = Promise.all([Promise.resolve(1), Promise.reject(2)]); // Promise {<rejected>: 2}
let p2 = Promise.all([new Promise(()=> {}), Promise.resolve(2)]); // Promise {<pending>}
let p3 = Promise.all([Promise.resolve(1), Promise.reject(2),Promise.reject(3)]); // Promise {<rejected>: 2}
- 有拒绝的就合成拒绝的Promise, 有pending的就合成pending状态的Promise;
- 以第一个拒绝的Promise理由就是合成的Promise对象的拒绝理由
- 会静默处理所有包含期约的拒绝操作
Promise.race()
这个方法同样是接收一个可迭代对象,返回一个新的Promise对象。它返回的这个Promise对象是一组集合中最先解决或拒绝的Promise的镜像。
let p = Promise.race([
Promise.resolve(1),
Promise.resolve(2)
])
// Promise {<fulfilled>: 1}
传入不同的参数情况同 Promise.all()一样,不多做解释。
这里就强调一点:Promise.race() 返回的新期约 是包装的第一个落定的期约结果,不管是解决还是拒绝平等对待。