手写Promise的静态方法
最近对promise原理的理解,手写下其中的静态方法。
手写Promise的静态方法
- 1. Promise.resolve
- 2. Promise.reject
- 3. Promise.all
- 4. Promise.any
- 5. Promise.race
- 6. Promise.allSettled
1. Promise.resolve
首先就是resolve方法,它会接收一个值,总是会将其转换为一个状态为fulfilled的Promise对象,如果传入的值本身就是Promise对象,那就直接返回。
了解原理代码便呼之欲出了:
Promise.resolve = function (value) {if (value instanceof Promise) {return value; // 当传入的是一个Promise对象时,直接返回}return new Promise(resolve => resolve(value)) // 否则返回一个状态为fulfilled的Promise
}
先对传入的value进行类型判断,使用instance of进行判断。instance of是通过原型链进行类型判断的,所以当value是Promise对象时,就会得到true,直接返回value即可;如果value不是Promise对象,那就返回一个新的Promise对象并且使用resolve包裹一下,就行了。
2. Promise.reject
reject方法就是与resolve方法相反的,总是会得到一个状态为rejected的promise对象,不一样的是,不管传入的value是什么,都返回一个状态为rejected的promise对象:
Promise.reject = function (value) {// 不管传入的是什么,直接返回一个状态为rejected的promisereturn new Promise((resolve, reject) => reject(value))
}
3. Promise.all
然后是all方法。
all方法会接收一个由Promise对象组成的数组,如果数组中的Promise对象状态都是fufilled,返回一个由这些Promise对象的值组成的新的状态为fufilled的promise;只要有一个失败就立即失败,返回一个状态为rejected的Promise,值为第一个失败的promise对象的值。
了解了原理,我们就来手写代码:
Promise.all = function (PromiseArr) {let i = 0, result = [] // i用来记录PromiseArr中成功的promise对象,result用来保存promise对象的值return new Promise((resolve, reject) => { // all方法会返回一个新的promise对象})
}
我们会使用一个i来记录PromiseArr中成功的promise对象个数,每成功一个i就加一,便把这个promise对象的值存放到result数组中。然后all最后一定会返回一个新的Promise,于是我们return new Promise。
Promise.all = function (PromiseArr) {let i = 0, result = [] // i用来记录PromiseArr中成功的promise对象,result用来保存promise对象的值return new Promise((resolve, reject) => { // all方法会返回一个新的promise对象PromiseArr.forEach((item, index) => { // 遍历传入的promise对象数组Promise.resolve(item)})})
}
然后我们遍历传入的PromiseArr数组,使用resolve方法将PromiseArr数组中的每个元素都转换为promise。如果item是promise,resolve方法会直接返回它;如果不是,返回一个promise对象。
于是,我们就可以在后面接then了:
Promise.all = function (PromiseArr) {let i = 0, result = [] // i用来记录PromiseArr中成功的promise对象,result用来保存promise对象的值return new Promise((resolve, reject) => { // all方法会返回一个新的promise对象PromiseArr.forEach((item, index) => { // 遍历传入的promise对象数组Promise.resolve(item).then(val => { // 利用resolve方法将promise数组中的元素都变为promisei++ // 每成功一个就加1result[index] = val // 按索引记录值if (i === PromiseArr.length) { // 当index等于promise数组长度时,说明全部成功,直接resolveresolve(result)}},err => {reject(err) // 只要有一个失败,立即失败})})})
}
当item状态是fufilled时,i就加一,并根据索引将item的值存放到result中,最后当i的值等于PromiseArr数组的长度时,说明PromiseArr数组每个promise都成功了,就resolve这个result数组;否则,只要有一个失败,就立即reject。
这样,一个基本的all方法我们就实现了。
4. Promise.any
any方法和all方法比较类似。any方法是当传入的promise数组每个状态都为rejected时返回一个状态为rejected的新Promise;否则,只要有一个状态为fufilled,就立即成功,返回第一个是 fulfilled 的新实例。
Promise.any = function (PromiseArr) {let i = 0 // 用来记录PromiseArr中失败的个数return new Promise((resolve, reject) => { // any方法会返回一个新的promise对象})
}
开头和all方法比较类似,我们使用一个i来记录PromiseArr数组中失败的个数,然后any方法会返回一个新的promise对象,于是我们就return new Promise。
Promise.any = function (PromiseArr) {let i = 0 // 用来记录PromiseArr中失败的个数return new Promise((resolve, reject) => { // any方法会返回一个新的promise对象PromiseArr.forEach((item, index) => { // 遍历PromiseArr数组Promise.resolve(item)})})
}
同样,我们使用resolve方法将数组中的每一项item都转化为promise对象。
Promise.any = function (PromiseArr) {let i = 0 // 用来记录PromiseArr中失败的个数return new Promise((resolve, reject) => { // any方法会返回一个新的promise对象PromiseArr.forEach((item, index) => { // 遍历PromiseArr数组Promise.resolve(item).then(val => { // 利用resolve方法将PromiseArr数组中的每个元素都变为promise对象resolve(val) // 只要有一个成功,立即成功},err => {i++ // 记录失败的次数if (i === PromiseArr.length) { // 当数组中全部失败时reject(new AggregateError('All promises were rejected'))}})})})
}
然后,每失败一次,i就加1。最后,当i等于PromiseArr数组的长度时,说明全部失败,就reject,值为 AggregateError 的错误;否则,只要有一个成功,立即成功。
这样,我们就实现了一个基本的any方法。
5. Promise.race
我们紧接着来手写一下race方法,race方法的原理是会返回第一个得出状态的promise的值,无论成功还是失败。
原理很简单,代码也比较简单:
Promise.race = function (PromiseArr) {return new Promise((resolve, reject) => { // race方法会返回一个新的promise对象PromiseArr.forEach((item, index) => { // 遍历处理PromiseArr中元素Promise.resolve(item).then(val => {resolve(val) // 返回第一个成功的},err => {reject(err) // 或者第一个失败的})})})
}
6. Promise.allSettled
我们来手写一下今天的最后一个静态方法,也是比较复杂的一个,allSettled。
它主要是用来观察一组promise对象数组发生的变化,所有 Promise 的状态都变化了,那么新返回一个状态是 fulfilled 的 Promise,且它的值是一个数组,数组的每项由所有 Promise 的值和状态组成的对象;
Promise.allSettled = function (PromiseArr) {let result = []return new Promise((resolve, reject) => {})
}
我们使用result数组来保存最后的结果,allSettled方法也会返回一个新的promise对象,于是我们return new Promise。
Promise.allSettled = function (PromiseArr) {let result = []return new Promise((resolve, reject) => {PromiseArr.forEach((item, index) => {Promise.resolve(item)})})
}
同样,使用resolve方法将数组的每一项转换为promise对象。
Promise.allSettled = function (PromiseArr) {let result = []return new Promise((resolve, reject) => {PromiseArr.forEach((item, index) => {Promise.resolve(item).then(val => {result.push({status: 'fulfilled',value: val,})if (result.length === PromiseArr.length) {resolve(result)}},err => {result.push({status: 'rejected',reason: err,})if (result.length === PromiseArr.length) {resolve(result)}})})})
}
我们将每一个item的值都存入到result数组中,并且要记录每个item的状态,allSettled总是返回一个状态为fufilled的新promise,最后,当result的长度等于PromiseArr的长度,说明处理完毕,直接resolve这个result数组。
这样,我们也实现了一个基本的allSettled方法。