Promise.all
根据上一篇博客中自己写的 Promise 完成 all 方法的实现,all 就是全部成功就 resolve,只要有一个抢先失败,就执行 reject。
由于自己实现的 Promise 与原生的不太一样,比如原生的 Promise.resolve 能解析普通值为 Promise。所以这里我们自己写一个是否为 Promise 函数来判断。具体代码如下:
//解决异步并发,同步处理结果
let Promise = require('./promise')
let fs = require('fs')
function read(url) {
let dfd = Promise.defer()
fs.readFile(url, 'utf8', function (err, data) {
if (err) dfd.reject(err)
dfd.resolve(data)
})
return dfd.promise
}
function isPromise(x) {
if (typeof x === 'object' && x !== null || typeof x === 'function') {
try {
let then = x.then //当前有then方法,姑且认为 x 是个Promise
if (typeof then === 'function') {
return true
}
} catch (err) {
return false
}
} else {
return false
}
}
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let len = promises.length
let arr = new Array(len)
let count = 0
function processData(i, data) {
arr[i] = data
count++
if (count === len) {
resolve(arr)
}
}
for (let i = 0; i < len; i++) {
current = promises[i]
if (isPromise(current)) {
current.then(data => {
processData(i, data)
}, err => {
reject(err)
})
} else {
processData(i, current)
}
}
})
}
Promise.all([1, 2, 3, read('./name.txt'), read('./age.txt'), 6, 7]).then(data => {
console.log(data)
}, err => {
console.log(err)
})
基于原生 Promise 的写法如下
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let len = promises.length
let fulfilledResult = new Array(len)
let count = 0
promises.forEach((promise, index) => {
Promise.resolve(promise).then(data => {
fulfilledResult[index] = data
count++
if (count === len) {
resolve(fulfilledResult)
}
}, error => {
reject(error)
})
});
})
}
Promise.prototype.finally
finally 的实现基于原生的 Promise。 finally 的特点是不管当前的 Promise 是成功还是失败,都会执行它接收的回调函数,对后面的 then 的使用无影响,也就是会发生值穿透,外加执行回调函数。
以下面代码为例,
let p = new Promise((resolve, reject) => {
resolve(1)
// reject(2)
})
p.finally(() => { //无论成功失败都执行,并且将状态进行传递
console.log('最终的')
}).then(data => {
console.log(data)
}).catch(err => {
console.log(err)
})
执行结果是
原理就是需要返回一个 Promise,这个新的 Promise 与当前 Promise 的状态一致,且成功值或者失败值一致。
回忆一下 then 方法的值穿透本质,我们只需要在穿透的中间,不管成功还是失败,执行一下 finally 接收的回调函数即可,代码如下
Promise.prototype.finally = function (cb) {
return this.then(data => {
cb()
return data
}, err => {
cb()
throw err
})
}
如果 finally 接收的回调函数中返回一个 Promise,而且其执行器中有异步代码,比如
let p = new Promise((resolve, reject) => {
resolve(1)
// reject(2)
})
p.finally(() => { //无论成功失败都执行,并且将状态进行传递
console.log('最终的')
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 4000)
})
}).then(data => {
console.log(data)
}).catch(err => {
console.log(err)
})
我们会发现原生的 Promise会等这个 Promise 执行完之后才会走下面的 then,这里我们要用到 Promise.resolve 去解析,先给出代码
Promise.finally = function (cb) {
return this.then(data => {
return Promise.resolve(cb()).then(() => data)
}, err => {
return Promise.resolve(cb()).then(() => {
throw err
})
})
}
这里为什么两层 return 和 then 呢?
- 外层的 return 为了返回一个值穿透的 Promise
- 如果 cb() 中返回 Promise, 内层的 Primise.resolve 会等待 cb()执行完,并解析这个 Promise,所以内层的 return 不仅能进行值穿透还能等到 cb执行完。
- 同时需要发生值穿透,使用
.then(() => data)
,利用闭包将 data 向后传递,这个 then 中返回值会被解析,本身是成功就成功,本身是失败就失败,所以依然是值穿透,也就是值经过了两层 then 的值穿透。
另外,mdn 给出一条注意:在finally回调中 throw(或返回被拒绝的promise)将以 throw() 指定的原因拒绝新的promise。只需要稍微修改一下即可:
Promise.finally = function (cb) {
return this.then(data => {
return Promise.resolve(cb()).then(() => data)
}, err => {
return Promise.resolve(cb()).then(() => {
throw err
}, err2 => {
throw err2
})
})
}
Promise.resolve
如果接收的参数是普通值,会把这个普通值作为成功值并包装成成功态的 Promise。如果接收的是 Promise,会等待 Promise 执行完之后再继续执行,其状态还是这个 Promise 的状态,可以认为是等待执行 + 值穿透。 简单测试下是否如此 成功的 Promise:
let p = new Promise((resolve, reject) => {
resolve(1)
})
Promise.resolve(p).then(data => {
console.log('success:' + data)
}, err => {
console.log('error:' + err)
})
结果为
失败的 Promise:
let p = new Promise((resolve, reject) => {
reject(1)
})
Promise.resolve(p).then(data => {
console.log('success:' + data)
}, err => {
console.log('error:' + err)
})
结果为
普通值:
Promise.resolve(1).then(data => {
console.log('success:' + data)
}, err => {
console.log('error:' + err)
})
好了,了解了基本特性之后,我们就可以简单实现自己的 resolve 了
Promise.resolve = function (value) {
return Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(data => {
resolve(data)
}, err => {
reject(err)
})
} else {
resolve(value)
}
})
}
如果接收的 Promise 的 resolve 接收的参数也是一个 Promise,那么需要再递归解析,这里就不实现了,这里的思路与上一篇博客中的 resolvePromise 的实现基本是一样的。
Promise.race
比较简单,就不介绍了,直接上代码
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach(promise => {
promise.then(data => {
resolve(data)
}, err => {
reject(err)
})
})
})
}
Promise.catch
Promise.catch 是 .then(null, rejection) 或 .then(undefined, rejection) 的别名
Promise.catch = function(onRejected){
return this.then(undefined,onRejected)
}