回调函数、回调地狱,异常函数 Promise / then 和 catch / async 与 await / try…catch 的应用

回调函数

把 函数1 通参数的形式传递给 函数2, 在函数2内部以形参方式调用,函数1就叫 函数2的回调函数 通常用到回调函数的场景都是在异步代码封装

  • 简单的回调函数

    把 函数A 通参数的形式传递给 函数B, 在函数B内部以形参方式调用,函数A就叫 函数B的回调函数

        function A () {
            console.log('函数A执行')
        }
        function B(cb) {
            console.log('函数B执行')
            cb()
        }
        B(A);  // A 函数作为实参 传入 b函数中   =>  先执行B函数 通过B函数内部调用A函数 
  • 封装 异步函数 1 => 一般都是网络请求
        function fun(f){
            const time = Math.ceil(Math.random()*3000);  
            /* 
            随机数 返回值作为倒计时器 时间 当时间到达0时 执行当前函数  当前函数执行完毕后 调用函数fu()  
            fu()再执行
            */
            setTimeout(() => {
                console.log('异步函数执行',time);
                f();
            },time)
            

        }

        fun(
            function fu(){   // 函数 fu() 在此时为实参 传入函数 fun() 中,在 fun() 内部调用
                console.log('异步函数执行完后再执行');  
            }
        )

image.png

  • 封装 异步函数 2

    封装一个形如网络请求的异步函数 , 通过随机数生成时间来判断来判断是否请求成功, 当请求大于某一时间,请求失败,反之则请求成功

        function fun(sb,cg){
            const time = Math.ceil(Math.random()*3000);  // 随机数 返回值作为倒计时器 时间 
            setTimeout(() => {
                // 当时间大于3500 时 判断请求失败
                if(time > 3500){
                    console.log('请求失败');
                    // 请求失败后调用sb函数
                    sb();
                }else{
                    console.log('请求成功');
                    // 请求成功 调用cg函数
                    cg();
                }
            },time);
        }


        fun(
            // 参数1
            () => {  
                console.log('请求失败,不能继续访问');
            },
            // 参数2
            () => {
                console.log('请求成功,可以继续访问');
            }
        )

image.png

回调地狱

 回调地狱并非一个 bug,而是一种代码格式,而这种代码格式不利于我们阅读 
 
 需求:在网络请求时,发出判断,如果时间大于请求时间,请求失败,不再请求,如果未超过请求时间,则请求成功,继续请求
        function fun(sb, cg) {
            const time = Math.ceil(Math.random() * 3000) + 2000;  // 随机数 返回值作为倒计时器 时间 
            setTimeout(() => {
                // 当时间大于3500 时 判断请求失败
                if (time > 3500) {
                    console.log('请求失败,时间:', time);

                    sb();
                } else {
                    console.log('请求成功,时间:', time);
                    // 请求成功 调用cg函数
                    cg();
                }
            }, time)


        }

        fun(
            // 参数1
            () => {
                console.log('第一次请求失败,不能继续访问');
            },
            // 参数2
            () => {
                console.log('第一次请求成功,可以继续访问');
                // 第一次请求成功  发出第二次请求
                fun(
                    () => {
                        console.log('第二次请求失败,不能继续访问');
                    },
                    () => {
                        console.log('第二次请求成功,可以继续访问');
                        // 第二次请求成功  发出第三次请求
                        fun(
                            () => {
                                console.log('第三次请求失败,不能继续访问');
                            },
                            () => {
                                console.log('第三次请求成功,可以继续访问');
                            }
                        )
                    }
                )
            }
        )

第一次访问成功,继续下一次,到达第二次以后,访问失败,不再继续访问
image.png

Promise

Promise (契约) 是解决回调地狱的一种方法

Promise 的三个状态
1. 持续: pending
2. 成功: fulfilled
3. 失败: rejected

  • resolve 会把我们这个 promise 状态转换为 成功
  • reject 会把我们这个 promise 状态转换为 失败

一个 Promise 是对一个异步操作的封装,异步操作有 等待成功 、成功和失败三个状态 ,对应了Promise的三个状态

promise 只会发生两个转换 (一旦转换完成就不能再改变)
1. 持续 ==> 成功
2. 持续 ==> 失败

    const P = new Promise( function(reslove,reject) {
            // resolve 会把我们这个 promise 状态转换为 成功
            // reject 会把我们这个 promise 状态转换为 失败   两个都是函数
            const time = Math.ceil(Math.random() * 3000) + 2000;  // 随机数 返回值作为倒计时器 时间 
            setTimeout(() => {
                // 当时间大于3500 时 判断请求失败
                if (time > 3500) {
                    console.log('请求失败,时间:', time);

                    reslove('失败!不能再继续访问')
                } else {
                    console.log('请求成功,时间:', time);
                    // 请求成功 调用cg函数
                    reject('成功!可以继续访问');
                }
            }, time)
        })

        console.log(P);

image.png

then / catch

  1. then 在Promise 成功时触发,并且接受 resolve 时传递的参数
  2. catch 在Promise 失败时触发,并且会接受 reject 时传递的参数
        const P = new Promise( function(reslove,reject) {
            // resolve 会把我们这个 promise 状态转换为 成功
            // reject 会把我们这个 promise 状态转换为 失败   两个都是函数
            const time = Math.ceil(Math.random() * 3000) + 2000;  // 随机数 返回值作为倒计时器 时间 
            setTimeout(() => {
                // 当时间大于3500 时 判断请求失败
                if (time > 3500) {
                    console.log('请求失败,时间:', time);

                    reject('失败!不能再继续访问')
                } else {
                    console.log('请求成功,时间:', time);
                    // 请求成功 调用cg函数
                    reslove('成功!可以继续访问');
                }
            }, time)
        })

        P.then(function(res){
            console.log('000',res);
        }).catch(function(res){
            console.log('111',res);
        })

image.png

  • 封装 Promise
        function fun(){
       
            const P = new Promise( function(reslove,reject) {
                // resolve 会把我们这个 promise 状态转换为 成功
                // reject 会把我们这个 promise 状态转换为 失败   两个都是函数
                const time = Math.ceil(Math.random() * 3000) + 2000;  // 随机数 返回值作为倒计时器 时间 
                setTimeout(() => {
                    // 当时间大于3500 时 判断请求失败
                    if (time > 3500) {
                        reject('失败!不能再继续访问')
                    } else {
                        // 请求成功 调用cg函数
                        reslove('成功!可以继续访问');
                    }
                }, time)
            })
            return P;  // 将 P 作为返回值 返回
        }

        fun().then((res) => {
            console.log('第一次请求成功,可继续访问');
        }).then((res) => {
            console.log('第二次请求成功,可继续访问');
        }).then((res) => {
            console.log('第三次请求成功,可继续访问');
        }).then((res) => {
            console.log('第四次请求成功,可继续访问');
        }).then((res) => {
            console.log('第五次请求成功,可继续访问');
        }).catch((res) => {
            console.log('请求失败,不能继续访问');
        })

image.png

async / await

作用: 能帮助我们把 异步代码, 写的和 同步代码一样
        function fun() {
            const P = new Promise(function (reslove, reject) {
                // resolve 会把我们这个 promise 状态转换为 成功
                // reject 会把我们这个 promise 状态转换为 失败   两个都是函数
                const time = Math.ceil(Math.random() * 3000) + 2000;  // 随机数 返回值作为倒计时器 时间 
                setTimeout(() => {
                    // 当时间大于3500 时 判断请求失败
                    if (time > 3500) {
                        reject('失败!不能再继续访问')
                    } else {
                        // 请求成功 调用cg函数
                        reslove('成功!可以继续访问');
                    }
                }, time)
            })
            return P;  // 将 P 作为返回值 返回
        }



        // 函数开头必须书写 async 表明内部可以书写 await
        async function newFun() {

            let p1 = await fun();
            console.log(p1);
            // 如果请求失败就执行 此行代码
            console.log('失败!');
        }
        newFun();  // 调用async 声明的函数

await 后边需要跟着 promise,await 表示等到的意思, 执行到 fun() 虽然是异步的,但是因为有 await 关键字, 此时不会往下继续执行,而是等待 fun() 执行完毕, 在往下执行

image.png

  • async/await 的问题
    1. 没有办法捕获到 错误, 只能接受 promise 的成功状态
    2. 如果报错, 会中断程序执行
      image.png
  • async/await 怎么抛出错误异常 ?

如果可能出错的代码比较少的时候可以使用try/catch结构来了处理,如果可能出错的代码比较多的时候,可以利
用async函数返回一个promise对象的原理来处理,给async修饰的函数调用后返回的promise对象,调用catch方
法来处理异常。

  • async/await 的问题 解决方法 1 ( try…catch )
    • try…catch

      首次执行的时候 会走 try 这个分支, 如果这个位置有报错,他会结束执行 try 分支, 然后走 catch 分支,如果再运行 try 分支的时候, 没有报错, 那么 catch 不会运行

        function fun() {

            const P = new Promise(function (reslove, reject) {
                // resolve 会把我们这个 promise 状态转换为 成功
                // reject 会把我们这个 promise 状态转换为 失败   两个都是函数
                const time = Math.ceil(Math.random() * 3000) + 3000;  // 随机数 返回值作为倒计时器 时间 
                setTimeout(() => {
                    // 当时间大于3500 时 判断请求失败
                    if (time > 3500) {
                        reject('失败!不能再继续访问')
                    } else {
                        // 请求成功 调用cg函数
                        reslove('成功!可以继续访问');
                    }
                }, time)
            })
            return P;  // 将 P 作为返回值 返回
        }

        
        async function newFun() {
            try{ // 如果请求成功  执行此分支
                let p1 = await fun();
                console.log(p1);
            }catch(error){ 
                // 请求失败 执行此分支 
                console.log(error);
                console.log('请求失败');
            }
        }
        newFun();  // 调用async 声明的函数

image.png

  • async/await 的问题 解决方法 2

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

      原因: promise 执行 reject 时 async await 不能捕获到错误,

      解决: 让这个 promise 不管什么情况 都返回 resolve

      我们通过 返回的 参数, 区分现在是成功还是失败,开发中 对象内的 code 如果为0, 一般代表失败,对象内的 code 如果为1, 一般代表成功

        function fun() {

            const P = new Promise(function (reslove, reject) {
                // resolve 会把我们这个 promise 状态转换为 成功
                // reject 会把我们这个 promise 状态转换为 失败   两个都是函数
                const time = Math.ceil(Math.random() * 3000) + 3000;  // 随机数 返回值作为倒计时器 时间 
                setTimeout(() => {
                    // 当时间大于3500 时 判断请求失败
                    if (time > 3500) {
                        reslove({
                            code:0,
                            msg:'请求失败,不能继续访问'
                        })
                    } else {
                        // 请求成功 调用cg函数
                        reslove({
                            code:1,
                            msg:'请求成功,可以继续访问'
                        });
                    }
                }, time)
            })
            return P;  // 将 P 作为返回值 返回
        }

        async function newFun(){
            const p1 = await fun();
            // console.log(p1.code);
            if(p1.code === 0){   // 如果code 为0  请求失败
                console.log('您的网络有问题');
            }else{    // 如果code 为1  请求成功   输出 msg 对应的值 
                console.log(p1.msg);
            }
           
        }
        newFun(); 
        
© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容