一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
Promise.prototype.finally
finally() 方法返回一个 Promise 。在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数
那怎么实现呢? 直接往 then 方法塞两个回调不就完事!
/**
* finally() 方法返回一个Promise。在promise结束时
* 无论结果是fulfilled或者是rejected,都会执行指定的回调函数
* @param {function} fn
* @returns promise
*/
Promise.prototype.finally = function (fn) {
return this.then(function (value) {
return Promise.resolve(fn()).then(function () {
return value
})
}, function (reason){
return Promise.reject(fn()).then(function () {
return reason
})
})
}
// ES6
Promise.prototype.finally = function (fn) {
return this.then(value => {
return Promise.resolve(fn()).then(() => value)
}, reason => {
return Promise.reject(fn()).then(() => reason)
})
}
这方法有啥用呢?比如你在处理异步请求的时候,经常会使用 loading,是不是事后无论请求成功或者失败都要把 loading 去掉,一般就是用在无论失败或成功都需要执行的操作
var load = false
new Promise(function (resolve, reject) {
load = true
setTimeout(function () {
console.log('in pending: ' + load) // in pending: true
if(Math.random() > 0.5){
resolve()
}else{
reject()
}
}, 100)
}).then(function(){
console.log('in fulfilled: ' + load) // in fulfilled: true
}).catch(function(){
console.log('in rejected: ' + load) // in rejected: true
}).finally(function () {
load = false
console.log('in finally: ' + load) // in finally: false
})
Promise.prototype.catch
这个其实没啥好讲的,其实等于 this.then(null, fn)
/**
* catch() 方法返回一个Promise,并且处理拒绝的情况。
* @param {function} fn
* @returns promise
*/
Promise.prototype.catch = function (fn) {
return this.then(null, fn)
}
使用方法极其简单
Promise.reject().catch(function(){
console.log('in catch')
})
Promise.reject & Promise.resolve
/**
* Promise.reject()方法返回一个带有拒绝原因的Promise对象
* @param {any} reason
*/
Promise.reject = function (reason) {
return new Promise(function(resolve, reject){
var fn = function () {
reject(reason)
}
if(reason instanceof Promise){
reason.then(fn, fn)
}else {
fn()
}
})
}
// ES6
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
const fn = () => reject(reason)
reason instanceof Promise ? reason.then(fn, fn) : fn()
})
}
Promise.reject(new Promise(res => {
console.log('in promise') // in promise
res(2)
})).then(v => console.log('in then ' + v))
.catch(v => console.log('in catch ', v)) // in catch Promise { 2 }
/**
* Promise.resolve(value)方法返回一个以给定值解析后的Promise 对象
* 如果这个值是一个 promise ,那么将返回这个 promise
* @param {any} reason
*/
Promise.resolve = function (value) {
if(value instanceof Promise) return value
return new Promise(function(resolve, reject){
resolve(value)
})
}
// ES6
Promise.resolve = function (value) {
return value instanceof Promise ? value :
new Promise(resolve => resolve(value))
}
Promise.resolve(new Promise((res, rej) => {
console.log('in promise') // in promise
res(2)
})).then(v => console.log('in then ' + v)) // in then 2
.catch(v => console.log('in catch ', v))
// 注意这里会有区别哦!
Promise.resolve(new Promise((res, rej) => {
console.log('in promise') // in promise
rej(2)
})).then(v => console.log('in then ' + v))
.catch(v => console.log('in catch ', v)) // in catch 2
接下来就是面试经常问到的四个方法了
Promise.all
Promise.all 是所有 Promise 结果都为 fulfilled 时才会执行 then 方法的回调!
值得注意的是,all 方法接收的是一个迭代器对象,很多实现代码上来就是一个 for 循环的写法是不对的!
/**
* Promise.all() 方法接收一个 promise 的 iterable 类型的输入
* 并且只返回一个Promise实例
* resolve([value,...])
* reject(firstReject)
* @param {*} iterable
* @returns promise
*/
Promise.all = function (iterable) {
return new Promise(function(resolve, reject){
var iteratee = iterable[Symbol.iterator]()
var len = 0
var i = 0
var res = null
var result = []
while (true){
res = iteratee.next()
if(res.done) break
!(function(j){
len++
var val = !(res.value instanceof Promise) ? Promise.resolve(res.value) : res.value
val.then(function(value){
result[j] = value
i++
if(len === i && res.done) resolve(result)
}, function(reason){
reject(reason)
})
})(len)
}
})
};
// ES6
Promise.all = function (iterable) {
return new Promise((resolve, reject) => {
const promiseList = [...iterable] // 转换可迭代对象为数组
const result = []
let j = 0
let len = promiseList.length
promiseList.forEach((val, i) => {
val = !(val instanceof Promise) ? Promise.resolve(val) : val
val.then(value => {
result[i] = value
j++
if(len <= j) resolve(result)
}, reason => reject(reason))
})
})
};
测试代码
[
new Map([[Promise.resolve(1), Promise.resolve(2)]]),
new Set([Promise.resolve(1), Promise.resolve(2)]),
[Promise.resolve(1), Promise.resolve(2)],
new Set([Promise.reject(1), Promise.resolve(2)]),
[Promise.reject(1), Promise.resolve(2)],
[1, '1', true, false, null, undefined, {}, function(){}, Symbol(), Promise.resolve(2)]
].forEach(item => {
Promise.all(item).then(v => {
console.log(v)
}).catch(r => {
console.log('in catch ' + r)
})
})
Promise.any
Promise.any 是只要有一个 Promise 结果都为 fulfilled 时就会执行 then 方法的回调!
/**
* Promise.any() 方法接收一个 promise 的 iterable 类型的输入
* 只要其中的一个 promise 成功,就返回那个已经成功的 promise
* resolve([value,...])
* reject(firstReject)
* @param {*} iterable
* @returns promise
*/
Promise.any = function (iterable) {
return new Promise(function(resolve, reject){
var iteratee = iterable[Symbol.iterator]()
var res = null
var len = 0
var i = 0
while (true){
res = iteratee.next()
if(res.done) break
len++
var val = !(res.value instanceof Promise) ? Promise.resolve(res.value) : res.value
val.then(function(value){
i++
resolve(value)
}, function(reason){
i++
if(i >= len && res.done){
reject(reason)
}
})
}
})
};
// ES6
Promise.any = function (iterable) {
return new Promise((resolve, reject) => {
const promiseList = [...iterable]
const len = promiseList.length
let i = 0
promiseList.forEach(val => {
val = !(val instanceof Promise) ? Promise.resolve(val) : val
val.then(value => {
i++
resolve(value)
}, reason => {
i++
if(i >= len){
reject(reason)
}
})
})
})
};
测试
[
new Map([[Promise.resolve(1), Promise.resolve(2)]]),
new Set([Promise.resolve(1), Promise.resolve(2)]),
[Promise.resolve(1), Promise.resolve(2)],
new Set([Promise.reject(1), Promise.resolve(2)]),
[Promise.reject(1), Promise.resolve(2)],
[1, '1', true, false, null, undefined, {}, function(){}, Symbol(), Promise.resolve(2)]
].forEach(item => {
Promise.any(item).then(v => {
console.log(v)
}).catch(r => {
console.log('in catch ' + r)
})
})
Promise.race
Promise.race 是只要有一个 Promise 产生结果时就会执行 then 方法的回调!
/**
* Promise.race(iterable) 方法返回一个 promise,
* 一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝
* resolve([value,...])
* reject(firstReject)
* @param {*} iterable
* @returns promise
*/
Promise.race = function (iterable) {
return new Promise(function(resolve, reject){
var iteratee = iterable[Symbol.iterator]()
var res = null
var done = false
while (true){
res = iteratee.next()
if(res.done) break
var val = !(res.value instanceof Promise) ? Promise.resolve(res.value) : res.value
val.then(function(value){
if(done) return
done = true
resolve(value)
}, function(reason){
if(done) return
done = true
reject(reason)
})
}
})
};
Promise.race = function (iterable) {
return new Promise(function(resolve, reject){
const promiseList = [...iterable]
let done = false
promiseList.forEach(val => {
val = !(val instanceof Promise) ? Promise.resolve(val) : val
val.then(value => {
if(done) return
done = true
resolve(value)
}, reason => {
if(done) return
done = true
reject(reason)
})
})
})
};
Promise.allSettled
Promise.allSettled 返回一个在所有给定的promise都已经fulfilled或rejected后的promise
/**
* Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise
* 并带有一个对象数组,每个对象表示对应的promise结果
* resolve([value,...])
* @param {*} iterable
* @returns promise
*/
Promise.allSettled = function (iterable) {
return new Promise(function(resolve){
var iteratee = iterable[Symbol.iterator]()
var res = null
var i = 0
var len = 0
var result = []
var allSettled = function(){
i++
if(len <= i && res.done) resolve(result)
}
while (true){
res = iteratee.next()
if(res.done) break
!(function(j){
var val = !(res.value instanceof Promise) ? Promise.resolve(res.value) : res.value
val.then(function(value){
result[j] = {
value: value,
status: 'fulfilled'
}
allSettled()
}, function(reason){
result[j] = {
reason: reason,
status: 'rejected'
}
allSettled()
})
}(len))
len += 1
}
})
};
Promise.allSettled = function (iterable) {
return new Promise(resolve => {
const promiseList = [...iterable]
const result = []
const len = promiseList.length
let j = 0
var allSettled = () => len <= ++j && resolve(result)
promiseList.forEach((val, i) => {
var val = !(val instanceof Promise) ? Promise.resolve(val) : val
val.then(value => {
result[i] = {
value: value,
status: 'fulfilled'
}
allSettled()
}, reason => {
result[i] = {
reason: reason,
status: 'rejected'
}
allSettled()
})
})
})
};
搞定收工!