侧边栏壁纸
博主头像
woku博主等级

成功的路上并不拥挤

  • 累计撰写 50 篇文章
  • 累计创建 13 个标签
  • 累计收到 3 条评论

Promise周边

woku
2022-06-14 / 0 评论 / 0 点赞 / 159 阅读 / 5,343 字

Promise.all

基本使用

接收一个数组作为参数

  • 数组中,每一个Promise必须全部成功,才是成功
const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        const data = {
            name: 'wyg',
            id: 1
        }
        resolve(data)
    }, 2000);
})
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('abc')
    }, 1000);
})
const p3 = 1

Promise.all([p1, p2, p3]).then(res => {
    console.log(res)
})

image.png

  • 有一个Promise是失败,整个就失败
const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        const data = {
            name: 'wyg',
            id: 1
        }
        resolve(data)
    }, 2000);
})
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('abc')
    }, 1000);
})
const p3 = 1

Promise.all([p1, p2, p3]).then(res => {
    console.log(res)
}, err => {
    console.log('error', err)
})

进入失败的回调,打印 error abc

image.png

实现

  static all(promiseArr) {
        let resArr = [],
            steps = 0
        return new MyPromise((resolve, reject) => {
            promiseArr.map((x, index) => {
                if (isPromise(x)) {
                    x.then(value => {
                        formatResArr(value, index, resolve)
                    }).catch(err => {
                        reject(err)
                    })
                } else {
                    formatResArr(x, index, resolve)
                }
            })
        })
        function formatResArr(value, index, resolve) {
            resArr[index] = value
            if (++steps === promiseArr.length) {
                resolve(resArr)
            }

        }
        function isPromise(x) {
            if ((typeof x === 'object' && x != null) || typeof x === 'function') {
                let then = x.then
                return typeof then === 'function'
            }
            return false
        }
    }

Promise.allSettled

基本使用

参数是一个可迭代对象
如果是Promise,不管成功还是失败,都会进行收集

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        const data = {
            name: 'wyg',
            id: 1
        }
        resolve(data)
    }, 2000);
})
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('abc')
    }, 1000);
})
const p3 = 1

Promise.allSettled([p1, p2, p3]).then(res => {
    console.log(res)
}, err => {
    console.log('error', err)
})
// [
//   { status: 'fulfilled', value: { name: 'wyg', id: 1 } },
//   { status: 'rejected', reason: 'abc' },
//   { status: 'fulfilled', value: 1 }
// ]

image.png

实现

判断promiseArr是不是一个可迭代对象

function isIterable(value) {
    return value != null && value !== undefined && typeof value[Symbol.iterator] === 'function'
}
    static allSettled(promiseArr) {
        let resArr = [],
            steps = 0
        return new Promise((resolve, reject) => {
            if (!isIterable(promiseArr)) {
                reject('type error')
            }
            if (promiseArr.length === 0) {
                resolve(promiseArr)
            }
            promiseArr.map((x, index) => {
                if (isPromise(x)) {
                    x.then(value => {
                        formatResArr('fulfilled', value, index, resolve)
                    }, reason => {
                        formatResArr('rejected', reason, index, resolve)
                    })
                } else {
                    formatResArr('fulfilled', x, index, resolve)
                }
            })
        })

        function formatResArr(status, value, index, resolve) {
            switch (status) {
                case 'fulfilled':
                    resArr[index] = {
                        status,
                        value
                    }
                    break;
                case 'rejected':
                    resArr[index] = {
                        status,
                        reason: value
                    }
                    break;
                default:
                    break;
            }
            if (++steps === promiseArr.length) {
                resolve(resArr)
            }
        }
    }

Promise.race

基本使用

race: 赛跑,谁先有结果,就拿谁的结果

参数也是一个可迭代对象

  • 可迭代对象中都是Promise
const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        const data = {
            name: 'wyg',
            id: 1
        }
        resolve(data)
    }, 2000);
})
const p2 = new Promise((resolve, reject) => {
    resolve('abc')
})
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('error')
    }, 1000);
})

Promise.race([p1, p2, p3]).then(res => {
    console.log(res)
}, err => {
    console.log('error', err)
})

p1p2p3三个Promise中,p2先有结果,那么Promise.race就拿p2的结果: abc

简单实现

    static race(promiseArr) {
        return new MyPromise((resolve, reject) => {
            if (!isIterable(promiseArr)) {
                reject('type error')
            }
            promiseArr.map(x => {
                if (isPromise(x)) {
                    x.then(value => {
                        resolve(value)
                    }, reason => {
                        reject(reason)
                    })
                } else {
                    resolve(x)
                }
            })
        })
    }

promise.finally

基本使用

  • finally是Promise原型上的一个方法
  • finally不管Promise的状态是成功还是失败,都要执行
  • finally回调不带参数
  • 正常走finally之后的then或者catch
Promise.resolve('promise success').finally(res => {
    console.log('finally', res)  // 'finally undefined'
}).then(value => {
    console.log('resolve', value)  // 'resolve promise success'
}, reason => {
    console.log('rejected', reason)
})
  • 如果finally内部有Promise,并且有延时操作,整个finally会等待
Promise.resolve('promise success').finally(res => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('finally success')
        }, 1000);
    })
   
}).then(value => {
    console.log('resolve', value)
}, reason => {
    console.log('rejected', reason)
})
// 等待1秒后打印 resolve promise success

在finally之前resolve了promise success,在finally内部又resolve了finally success。
最后返回的Promise的结果是取外面的还是取里面的呢?

  • 外面是成功,里面也是成功,取外面的成功结果
  • 外面是成功,里面是失败,取里面失败的结果
Promise.resolve('promise success').finally(res => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('finally error')
        }, 1000);
    })
   
}).then(value => {
    console.log('resolve', value)
}, reason => {
    console.log('rejected', reason)
})
// 走失败回调
// 打印 rejected finally error
  • 外面的是失败,里面的是成功,取外面失败的结果
Promise.reject('promise error').finally(res => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('finally success')
        }, 1000);
    })
   
}).then(value => {
    console.log('resolve', value)
}, reason => {
    console.log('rejected', reason) // rejected promise error
})
  • 外面的是失败,里面的也是失败,取里面失败的结果
Promise.reject('promise error').finally(res => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('finally error')
        }, 1000);
    })
   
}).then(value => {
    console.log('resolve', value)
}, reason => {
    console.log('rejected', reason)
})

外面和里面有一个是失败,就是失败(取最近的失败结果)
外面和里面都是成功,就是成功

实现

  1. finally执行,相当于一个`then``。 -> 正常走finally之后的then或者catch
  2. 无论成功还是失败,finally回调函数都要执行,也就是在then的onFulfilledonRejected都要走MyPromise.resolve(finallyCallback())
  3. onFulfilled(外面是成功的),当里面的MyPromise.resolve(finallyCallback())也是成功的话,返回外面的
  4. 如果MyPromise.resolve(finallyCallback())是失败,就会进入下一个then中的onRejected
  5. 外面是失败的时候,进入onRejected,里面MyPromise.resolve(finallyCallback())是成功的话,在本次的then里面抛出异常,值为外面失败的原因
  6. 外面是失败,里面也是失败,不会进入里面的then的onFulfilled处理,进入下一个then中的onRejected
    finally(finallyCallback) {
        return this.then(value => {
            return MyPromise.resolve(finallyCallback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(finallyCallback()).then(() => {
                throw reason
            })
        })
    }
0

评论区