Promise解决Js函数回调地狱

164 阅读4分钟

「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」。

嗨,大家好,我是Starqin,昨天趁着周六的时间,回顾了以下Promise,今天借着写这篇文章的机会,再来复习一遍

Promise英译汉的意思是承诺、保证的意思。

Promise有三种状态,我分别用代码来引导出来

等待状态

let myPro = new Promise((res, rej) => {});
console.log(myPro);

上面这段代码实例化了一个promise对象,并且没有对promise进行任何操作。此时控制台中输出以下内容

图片.png 黄色方框中PromiseState的值是pending。表示Promise进入等待状态

注意在实例化Promise时我们需要在构造函数中传入一个带有两个参数的回调函数,其中第一个参数,表示成功,第二个参数表示失败,这两个参数,您可以自定义名称,但是他们所代表的逻辑您无法改变。

成功状态

let myPro = new Promise((res, rej) => {
    res();
});
console.log(myPro);

当我在Promise构造函数回调方法中调用第一个参数时,控制台输出如下:

图片.png 黄色方框中PromiseState的值是fulfilled。表示Promise进入成功状态状态 接着我在调用res时,传递一个参数

let myPro = new Promise((res, rej) => {
    res("W-js are you ok?");
});
console.log(myPro);

此时控制台中的输出,如下

图片.png 可以看到,PromiseResult的值不再是undfined,而是我们在调用res函数时传递的参数

失败状态

let myPro = new Promise((res, rej) => {
    rej("乌克兰怎么啦?");
});
console.log(myPro);

控制台输出如下:

图片.png

当我们调用rej函数时,PromiseState的值为rejected,表示promise进入失败状态,并且会给我们报一个错误,PromiseResult的值是我们传递给rej函数的参数

then方法

每一个Promise对象都有一个then方法,then方法又有两个回调函数,onResoLved、onRejected,其中onResoLved是当Promise对象状态为成功时调用的函数,onRejected是Promise对象状态为失败时调用的函数。

<script>
        let myPro = new Promise((res, rej) => {
            rej("乌克兰怎么啦?");
        });
        
        myPro.then(
            () => {
                console.log('Promise处于成功状态');
            }, () => {
                console.log("promise处于失败状态")
            })
    </script>

控制台输出

图片.png 当我们在Promise构造函数中调用res函数时,控制台的输出结果:

图片.png

注意then方法中的两个回调函数,是可以接收参数的,且这个参数就是Promise中调用res或rej的参数,请看一下代码

<script>
        let myPro = new Promise((res, rej) => {
            res("W-js are you ok?");
            //rej("乌克兰怎么啦?");
        });
        
        myPro.then(
            (myRes) => {
                console.log(myRes,'当然,我Js很好');
            }, () => {
                console.log("promise处于失败状态")
            })
    </script>

控制台的输入结果

图片.png

then也是有返回值,其返回值无论在什么状态下都会返回一个Promise对象,这样的呃特性,也就导致Promise可以进行链式操作

Promise实操

我有以下代码,需要在输出111后在输出222,然后在输出333

    function app1() {
            setTimeout(() => {
                console.log(111);
            }, 1000)
        }
        
     function app2() {
            setTimeout(() => {
                console.log(222);
            }, 1000)
        }

      function app3() {
            setTimeout(() => {
                console.log(333);
            }, 1000)
        }

有的人肯第一时间会这样解答:

    app1();
    app2();
    app3();

依次调用这些函数,控制台中的输出结果

图片.png 虽然表面上是实现了这样的效果,但是实际上,由于setTimeout中的回调函数是一个异步代码,且等待时间是一秒钟。这也就导致111,222,333是同一时间被输出的,没有达到最终的要求

此时我们原生的解决方法是

        function app1() {
            setTimeout(() => {
                console.log(111);
                app2();
            }, 1000)
        }

        function app2() {
            setTimeout(() => {
                console.log(222);
                app3()
            }, 1000)
        }


        function app3() {
            setTimeout(() => {
                console.log(333);
            }, 1000)
        }
        app1();

这样的操作结果就能够达到要求,111,222,333是被依次输出到控制台的,但是如果我将上面这段代码改写成以下这种形式

    <script>
        function app1() {
            setTimeout(() => {
                console.log(111);
                setTimeout(() => {
                    console.log(222);
                    setTimeout(() => {
                        console.log(333);
                    }, 1000)
                }, 1000)
            }, 1000)
        }

        app1();
    </script>

大家可以看到这样的写法虽然直观,但是代码嵌套关系复杂,嵌套结构很深,我们称这种状况为回调地狱,而promise就是为了解决回调地狱应运而生的

将以上代码改写成Promise

    function app1() {
            return new Promise((res) => {
                setTimeout(() => {
                    res('111')
                }, 1000)
            })
        }


        app1().then(res => {
            console.log(res);
            return new Promise((res) => {
                setTimeout(() => {
                    res('222')
                }, 1000)
            })
        }).then(res => {
            console.log(res);
            return new Promise((res) => {
                setTimeout(() => {
                    res('333')
                }, 1000)
            })
        }).then(res => {
            console.log(res);
        })

上面的这种代码结构极大程度解决了回调函数的嵌套问题

以上代码优化:

    <script>
        function app1(text) {
            return new Promise((res) => {
                setTimeout(() => {
                    res(text)
                }, 1000)
            })
        }


        app1(111).then(res => {
            console.log(res);
            return app1(222);
        }).then(res => {
            console.log(res);
            return app1(333)
        }).then(res => {
            console.log(res);
        })
    </script>

IMG_20220227_103852.jpg