Promise.all()
Promise.all() 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise
实例, 那个输入的所有promise的resolve回调的结果是一个数组。
这个Promise
的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。
简单理解:所有都成功才成功,有一个失败就失败了
举例
Promise.all([1, 2, 3, new Promise((resolve, reject) => {
resolve('成功')
}), new Promise((resolve, reject) => {
resolve('失败')
})
]).then(values => {
console.log('成功', values)
}).catch(e => {
console.log('e', e)
})
//结果
//成功 [ 1, 2, 3, '成功', '失败' ]
复制代码
若我们将最后一个Promise的结果改为reject('失败')
,即
Promise.all([1, 2, 3, new Promise((resolve, reject) => {
resolve('成功')
}), new Promise((resolve, reject) => {
reject('失败')
})
]).then(values => {
console.log('成功', values)
}).catch(e => {
console.log('e', e)
})
//结果
// e '失败'
复制代码
下面是手写Promise.all的方法
首先我们要判断Promise.all参数数组中的传值类型是不是一个Promise
function isPromise (value) {
if (typeof value === 'function' || (typeof value === 'object' && value !== null)) {
if (typeof value.then === 'function') {
return true
}
}
return false
}
复制代码
下面是Promise.all的实现方法
Promise.all = function (values) {
return new Promise((resolve, reject) => {
// result[3] = 2 result.length = 4,所以我们不能简单的用result.length来判定是否所有的Promise都执行完成,而应该采用计时器累加的方法
let result = []
let times = 0;
const postSuccess = (i, value) => {
result[i] = value
if (++times === values.length) {
resolve(result)
}
}
for (let i = 0; i < values.length; i++) {
const current = values[i]
if (isPromise(current)) {
current.then(value => {
postSuccess(i, value)
}).catch(e => {
reject(e)
})
} else {
postSuccess(i, current)
}
}
})
}
复制代码
Promise.race()
Promise.race(iterable)
方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
简单理解:有一个成功或者失败就采用它的结果
虽然**Promise.race(iterable)
** 使用的场景并不多,但是我们可以用它做一些简单的超时处理
race的译文为赛跑,即采用最快的那一个,race方法如果其中一个完成了,其他的还是会执行的,只是并没有采用它的结果
Promise.race = function (values) {
return new Promise((resolve, reject) => {
for (let i = 0; i < values.length; i++) {
const current = values[i]
if (isPromise(current)) {
current.then(resolve, reject)//一旦成功就直接停止
} else {
resolve(current)
}
}
})
}
复制代码
测试
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 4000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败')
}, 2000)
})
Promise.race([p1, p2]).then(values => {
console.log('成功', values)
}).catch(e => {
console.log('e', e)
})
// 可以修改p1和p2的结果测试
复制代码
实际应用,图片加载超时问题,脚本加载超时问题
// 如何终止一个promise (中断promise) promise 超时
// race 的特点就是一个失败了就失败了,那我们可以构造一个自己的Promise和原Promise放在一起
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 3000);
})
function wrap (promise) {
let abort;
let newPromise = new Promise((resolve, reject) => {
// 创建了一个promise,暴露一个终端方法
abort = reject;
});
let p = Promise.race([newPromise, promise]);
p.abort = abort;
return p;
}
let p1 = wrap(p);
setTimeout(() => {
// 让这个promise 变成失败态
p1.abort('超过2s了');
}, 2000);
p1.then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
复制代码
Promise.prototype.finally()
finally()
方法返回一个Promise
。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise
是否成功完成后都需要执行的代码提供了一种方式。
这避免了同样的语句需要在then()
和catch()
中各写一次的情况。
简单理解:finally 的特点 无论如何都执行 ,但是如果返回的是一个promise需要等待这个promise之行完在继续向下执行
例如
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功了')
}, 2000)
}).finally(() => {// => then, 无论状态如何都会执行
console.log('finally')
}).then(data => {
console.log('data', data)
})
// finally
// data 成功了
复制代码
finally后面还可以.then .then 所以finally本质上就是一个then
实现
Promise.prototype.finally = function (cb) {
return this.then((data) => {
// 如何保证Promise.then能够执行完毕
return Promise.resolve(cb()).then((n) => data);
}, (err) => {
// Promise.resolve 目的是等待cb()后的Promise执行完成
return Promise.resolve(cb()).then((n) => { throw err });
})
}
复制代码