zl程序教程

您现在的位置是:首页 >  工具

当前栏目

【学习笔记72】 Promise和async 与 await

笔记学习async Promise await 72
2023-09-11 14:14:57 时间

一、Promise

  • 一个新的异步代码封装方案
  • 以前通过回调函数的形式去封装, 会导致出现回调地狱
  • 现在换promise 后, 就解决了这个问题

1、promise 它会有三个状态

  • 持续: pending
  • 成功: fulfilled
  • 失败: rejected

2、promise 只会发生两个转换

  • 持续 ==> 成功
  • 持续 ==> 失败

3、promise实例化对象的方法

  • .then
  • .catch

4、代码的实现

        const p = new Promise(function (resolve, reject) {
            /**
             *  resolve 会把我们这个 promise 状态转换为 成功
             *  reject 会把我们这个 promise 状态转换为 失败
             * 
             *      这两个 都是 函数
            */
            console.log('班长帮我去买一瓶水')
            const timer = Math.ceil(Math.random() * 3000) + 2000
            setTimeout(() => {
                if (timer > 3500) {
                    console.log('班长买水失败', timer)

                    reject('班长买水失败, 再换个地方买')
                } else {
                    console.log('班长买水成功', timer)

                    resolve('班长买水成功, 奖励二十个bug')
                }
            }, timer)

        })

        p.then(function (res) {
            // promise 成功状态时触发
            //并且接受resolve时传递的参数
            console.log(res);
        })

        p.catch(function (res) {
            // promise失败状态时触发
            // 并且接受reject时传递的参数
           console.log(res);
        })

5、promise实例化对象可以接受链式调用

        const p = new Promise(function (resolve, reject) {
            console.log('班长帮我去买一瓶水')
            const timer = Math.ceil(Math.random() * 3000) + 2000
            setTimeout(() => {
                if (timer > 3500) {
                    console.log('班长买水失败', timer)

                    reject('班长买水失败, 再换个地方买')
                } else {
                    console.log('班长买水成功', timer)

                    resolve('班长买水成功, 奖励二十个bug')
                }
            }, timer)

        })

        p.then(function (res) {
            console.log(res)
        }).catch(function (res) {
            console.log(res)
        })

二、封装promise

  • promise.then内部return了一个新的 promise对象
  • 可以在后续再写几个 .then
        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 2000
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('班长买水失败, 再换个地方买')
                    } else {
                        resolve('班长买水成功, 奖励二十个bug')
                    }
                }, timer)

            })
            return p
        }

        fn().then((res) => {
            console.log('班长第一次买水成功')
            return fn()
        }).then((res) => {
            console.log('班长第二次买水成功')
            return fn()
        }).then((res) => {
            console.log('班长第三次买水成功')
        }).catch((res) => {
            console.log('班长买水失败')
        })

三、async 与 await

  • 作用: 能帮助我们把异步代码, 写的和同步代码一样
        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000)
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('班长真好, 就是买水失败, 再换个地方买')
                    } else {
                        resolve('班长真好, 就是买水成功, 奖励二十个bug')
                    }
                }, timer)

            })
            return p
        }


        // 1. 函数开头必须书写async表明内部可以书写await
        async function newFn() {
            /**
             *  await 后边需要跟着promise
             *      await表示等到的意思, 执行到fn(),虽然是异步的
             *      但是因为有await关键字, 此时不会往下继续执行, 
             *      而是等待 fn()执行完毕, 在往下执行
            */
            let r1 = await fn()
            console.log(r1) 
            // console.log('如果失败了, 执行这行代码, 提示用户网络有问题')
        }
        newFn()

四、async与await的问题

  • 没有办法捕获到错误, 只能接受promise的成功状态
  • 如果报错, 会中断程序执行

解决方法1: try...catch

  • 首次执行的时候,会走try这个分支, 如果这个位置有报错
  • 他会结束执行try分支, 然后走catch分支
  • 如果再运行try分支的时候, 没有报错, 那么catch不会运行
        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 2000
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('班长真好, 就是买水失败, 再换个地方买')
                    } else {
                        resolve('班长真好, 就是买水成功, 奖励二十个bug')
                    }
                }, timer)

            })
            return p
        }

        async function newFn() {
            try {
                let r1 = await fn()
                console.log(r1)
            } catch (error) {
                console.log(error)
            }
        }
        newFn()

解决方法2: 更改 promise 的封装

  • 原因: promise执行reject时,async await不能捕获到错误,
  • 解决: 让这个promise不管什么情况都返回resolve,我们通过返回的参数, 区分现在时成功还是失败
  • 开发中,对象内的code如果为0, 一般代表失败;对象内的code如果为1, 一般代表成功
        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 1000
                setTimeout(() => {
                    if (timer > 3500) {
                        // reject('班长真好, 就是买水失败, 再换个地方买')
                        resolve({
                            code: 0,
                            msg: '班长真好, 就是买水失败, 再换个地方买'
                        })
                    } else {
                        resolve({
                            code: 1,
                            msg: '班长真好, 就是买水成功, 奖励二十个bug'
                        })
                    }
                }, timer)

            })
            return p
        }
        async function newFn() {
            let r1 = await fn()
            if (r1.code === 0) {
                console.log('您的网络有问题')
            } else {
                console.log(r1.msg)
            }
        }
        newFn()

五、promise的其他方法

(一)finally

  • promise 实例化对象还有一个方法(finally)
        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 2000
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('失败')
                    } else {
                        resolve('成功')
                    }
                }, timer)

            })
            return p
        }

        fn().then(res => {
            console.log('成功了: ', res)
        }).catch(res => {
            console.log('失败了: ', res)
        }).finally(res => {
            console.log('不管成功还是失败,都会执行')
        })

 (二)Promise构造函数上也有一些方法

1、all

  • all接受一个数组, 数组内可以传递多个promise对象
  • all方法的状态取决数组内部的promise对象的状态
  • 如果都是成功, all方法也是成功
  • 如果有一个失败, all方法就是失败
        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 2000
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('失败')
                    } else {
                        resolve('成功')
                    }
                }, timer)

            })
            return p
        }

        Promise.all([fn(), fn(), fn()])
            .then(res => {
                console.log('如果我输出, 代表所有promise对象都是成功状态')
            })
            .catch(res => {
                console.log('如果我输出, 代表最少有一个promise状态为失败状态')
            })

2、race

  • race接受一个数组, 数组内可以传递多个 promise 对象
  • race 方法的状态取决于,数组内部的 promise 对象中第一个结束
  • 如果第一个结束时是成功, race 就是成功
  • 如果第一个结束时时失败, race 就是失败
        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 2000
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('失败')
                    } else {
                        resolve('成功')
                    }
                }, timer)

            })
            return p
        }


        Promise.race([fn(), fn(), fn()])
            .then(res => {
                console.log('如果我执行, 代表数组内第一个结束的promise状态为成功')
            })
            .catch(res => {
                console.log('如果我执行, 代表数组内第一个结束的promise状态为失败')
            })

3、allSettled

  • allSettled 接受一个数组, 数组内可以传递多个 promise
  • 只会执行 .then, 接收到的参数是一个数组形式的, 内部元素为对应的promise的状态
        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 2000
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('失败')
                    } else {
                        resolve('成功')
                    }
                }, timer)

            })
            return p
        }

        Promise.allSettled([fn(), fn(), fn(), fn()])
            .then(res => {
                console.log(res)
            })

4、强行帮我们返回一个成功状态的 promise 对象

        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 2000
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('失败')
                    } else {
                        resolve('成功')
                    }
                }, timer)

            })
            return p
        }

        Promise.resolve()   
            .then(res => {
                console.log('成功')
            }).catch(res => {
                console.log('失败')
            })

5、强行帮我们返回一个失败状态的promise 对象

        function fn() {
            const p = new Promise(function (resolve, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 2000
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('失败')
                    } else {
                        resolve('成功')
                    }
                }, timer)

            })
            return p
        }

        Promise.reject()    
            .then(res => {
                console.log('成功')
            }).catch(res => {
                console.log('失败')
            })