浅层次理解Promise思想及其简单应用

在学习王世元老师的vue教程过程中,穿插着复习了一下Promise的内容。


引言

①什么是Promise?
一个ES6中非常重要和好用的特性
②Promise的用途?
Promise是异步编程的一种解决方案
③什么时候会处理异步事件?
在这里插入图片描述
但是网络请求非常复杂时,就会出现回调地狱

网络请求的回调地狱

在这里插入图片描述
看似只是几层回调函数的嵌套,但是在实际数据请求的时候我,可能并不是这么简单。
ex:每次调用前实际都会进行很多其他的操作
在这里插入图片描述
若在每个回调函数中除了回调另外一个函数,还有如以上例子一样的其他操作,就会使得代码变得臃肿,进而难以维护。
在这里插入图片描述
问题所在:
在这里插入图片描述


如何避免这个问题?

利用Promise完美的解决这个问题。

Promise实际是对异步操作的封装。
先来体会一下链式编程的思想(还没有真正实际使用Promise,只是用它来封装)

回调地狱举例如下:
我们将setTimeout模拟成网络请求

<script>
        // 1.使用setTimeout
        // setTimeout(() => {
    
    
        //     console.log('hello');
        // }, 1000);

        // 参数 -> 函数(resolove,reject)
        // resolve,reject本身又是函数
        new Promise((resolve, reject) => {
    
    
            setTimeout(() => {
    
    
                console.log('Hello world');
                console.log('Hello world');
                console.log('Hello world');
                console.log('Hello world');
                console.log('Hello world');

                setTimeout(() => {
    
    
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');

                    setTimeout(() => {
    
    
                        console.log('Hello Python');
                        console.log('Hello Python');
                        console.log('Hello Python');
                        console.log('Hello Python');
                        console.log('Hello Python');
                    }, 1000);
                }, 1000);
            }, 1000);
        })
    </script>

②为了避免回调地狱,这部分代码就需要被抽离。

// 参数 -> 函数(resolove,reject)
        // resolve,reject本身又是函数
        new Promise((resolve, reject) => {
    
    
            setTimeout(() => {
    
    
                // 一旦调用resolve(),则会在Promise后面自动调用.then(),
                //而then()中也是一个函数
                resolve()
            }, 1000);
        }).then(()=>{
    
    

        })

③再将刚刚出现回调地狱的代码放入then()中

new Promise((resolve, reject) => {
    
    
            setTimeout(() => {
    
    
                // 一旦调用resolve(),则会在Promise后面自动调用.then(),而then()中也是一个函数
                resolve()
            }, 1000);
        }).then(()=>{
    
    
            console.log('Hello world');
                console.log('Hello world');
                console.log('Hello world');
                console.log('Hello world');
                console.log('Hello world');

                setTimeout(() => {
    
    
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');

                    setTimeout(() => {
    
    
                        console.log('Hello Python');
                        console.log('Hello Python');
                        console.log('Hello Python');
                        console.log('Hello Python');
                        console.log('Hello Python');
                    }, 1000);
                }, 1000);
        })

④但是这里依旧还是有回调地狱,因此继续抽离。

new Promise((resolve, reject) => {
    
    
            // 第一次网络请求的代码
            setTimeout(() => {
    
    
                // 一旦调用resolve(),则会在Promise后面自动调用.then(),而then()中也是一个函数
                resolve()
            }, 1000);
        }).then(()=>{
    
    
            // 第一次拿到结果的处理代码
            console.log('Hello world');
                console.log('Hello world');
                console.log('Hello world');
                console.log('Hello world');
                console.log('Hello world');

                return new Promise((resolve,reject)=>{
    
    
                    // 第二次网络请求的代码
                    setTimeout(() => {
    
    
                    resolve()
                }, 1000);
                }).then(()=>{
    
    
                    // 第二次处理的代码
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');
                    console.log('Hello Vuejs');

                    return new Promise((resolve,reject)=>{
    
    
                        // 第三次网络请求的代码
                        setTimeout(() => {
    
    
                        resolve()
                    }, 1000);
                    }).then(()=>{
    
    
                        // 第三次处理的代码
                        console.log('Hello Python');
                        console.log('Hello Python');
                        console.log('Hello Python');
                        console.log('Hello Python');
                        console.log('Hello Python');
                    })
                })
        })

是不是感觉这样书写以后更加复杂了?
但是仔细看,虽然代码变得复杂了,但是逻辑上却更加清晰,每一次网络请求都是放在一个Promise对象内部。(请求代码在Promise内部,而请求的处理代码则是在Promise.then中)


什么时候用到Promise?
一般是有异步操作时,使用Promise对这个异步操作进行封装

	//模板
		// new ->构造函数(1.保存某些状态信息 2.执行传入的函数)
        // 在执行传入的回调函数时,会传入两个参数,resolve,reject,而这两个又是函数
        new Promise((resolve,reject)=>{
    
    
            setTimeout((data) => {
    
    
                // resolve中传什么,后面的then中就传什么
                resolve(data)
            }, 1000);
        }).then((data)=>{
    
    

        })

Promise的基本使用代码

        new Promise((resolve,reject)=>{
    
    
            setTimeout(() => {
    
    
                // resolve中传什么,后面的then中就传什么
                resolve('Hello World')
            }, 1000);
        }).then((data)=>{
    
    
            //处理代码
            console.log(data);
            console.log(data);
            console.log(data);
            console.log(data);
        })

运行结果如下:
在这里插入图片描述

上面只是利用了Promise中的resolve函数,但是什么时候会利用到后面的reject函数呢?
实际上第一个参数resolve是映射到成功执行的内容,而第二个参数reject则是执行失败的内容。

new Promise((resolve,reject)=>{
    
    
            setTimeout(() => {
    
    
                // 成功的时候调用resolve,并执行后面的then()内容

                // resolve中传什么,后面的then中就传什么
                // resolve('Hello World')

                // 失败的时候调用reject,并执行后面的catch()内容
                reject('error message')
            }, 1000);
        }).then((data)=>{
    
    
            //成功处理代码
            console.log(data);
            console.log(data);
            console.log(data);
            console.log(data);
        }).catch((err)=>{
    
    
            // 失败处理代码
            console.log(err);
        })

执行结果如下:
在这里插入图片描述
因此可以得出如此的思路图
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201208102754212.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTY2NDQwMg==,size_16,color_FFFFFF,t_70在这里插入图片描述


Promise的三种状态
在这里插入图片描述


Promise的另外一种写法

拒接和满足都写在then中,即then中包含两个参数

<script>
        new Promise((resolve,reject)=>{
    
    
            setTimeout(() => {
    
    
                // resolve('Hello vuejs')
                reject('error message')
            }, 1000);
            // 拒接和满足都写在then中,即then中包含两个参数
        }).then(data=>{
    
    
            console.log(data);
        },err=>{
    
    
            console.log(err);
        })
    </script>

Promise的链式调用简写
在这里插入图片描述

需求如下:
// 网络请求:aaa -> 自己处理10行
// 处理 aaa111 ->自己处理10行
// 处理 aaa111222 ->自己处理10行

<script>
        // 网络请求:aaa -> 自己处理10行
        // 处理 aaa111 ->自己处理10行
        // 处理 aaa111222 ->自己处理10行
        new Promise((resolve,reject)=>{
    
    
            setTimeout(() => {
    
    
                resolve('aaa')
            }, 1000);
        }).then((res)=>{
    
    
            // 自己处理10行
            console.log(res,'第一层的十行处理代码');

            // 2.
            return new Promise((resolve)=>{
    
    
                resolve(resolve+'111')
            }).then(res=>{
    
    
                console.log(res,'第二层的10行处理代码');

                return new Promise((resolve)=>{
    
    
                    resolve(res+'222')
                }).then(res=>{
    
    
                    console.log(res,'第三层的10行处理代码');
                })
            })
        })
    </script>

我们可以看到,这个代码块中,只有第一层是用了异步的,其他的时候都没有用异步。
那有没有针对于这种情况下的写法呢?

②省略掉new Promise()
写法如下:
即 不用再new一个 直接用Promise.resolve()来进行处理

new Promise((resolve, reject) => {
    
    
            setTimeout(() => {
    
    
                resolve('aaa')
            }, 1000);
        }).then(res => {
    
    
            // 自己处理10行
            console.log(res, '第一层的十行处理代码');

            // 2.
            return Promise.resolve(res + '111')
        }).then(res => {
    
    
            console.log(res, '第二层的10行处理代码');

            return Promise.resolve(res + '222')
        }).then(res => {
    
    
            console.log(res, '第三层的10行处理代码');
        })

执行结果如下:
在这里插入图片描述
但是依旧有些冗余,因此继续简化。
③省略掉Promise.resolve(),直接return
之所以可以这么做是因为,在直接return时,它内部会自动对这个内容进行Promise包装。

new Promise((resolve, reject) => {
    
    
            setTimeout(() => {
    
    
                resolve('aaa')
            }, 1000);
        }).then(res => {
    
    
            // 自己处理10行
            console.log(res, '第一层的十行处理代码');

            // 2.
            return (res + '111')
        }).then(res => {
    
     
            console.log(res, '第二层的10行处理代码');

            return (res + '222')
        }).then(res => {
    
    
            console.log(res, '第三层的10行处理代码');
        })

④若是reject,简写方法步骤雷同
(也可以用抛出异常 throw 效果相同)

在这里插入代码片// 失败
        new Promise((resolve, reject) => {
    
    
            setTimeout(() => {
    
    
                resolve('aaa')
            }, 1000);
        }).then(res => {
    
    
            // 自己处理10行
            console.log(res, '第一层的十行处理代码');

            // 用reject或者抛出异常throw 'error message'都可以
            // return Promise.reject('error message')
            throw 'error message'
        }).then(res => {
    
    
            console.log(res, '第二层的10行处理代码');

            return Promise.resolve(res + '222')
        }).catch(err => {
    
    
            console.log(err);
        })

执行结果如下:
在这里插入图片描述


若多个请求完成后才能返回
利用:Promise.all(迭代器).then(结果数组)

注:这里主要是理解这种思路

<script>
        // 若某个的返回条件是 需要多个请求结果
        // all中的参数是一个数组,数组中放了多个请求
        Promise.all([
            new Promise((resolve,reject)=>{
    
    
                $ajax({
    
    
                    url:'url1',
                    success:function(data){
    
    
                        resolve(data)
                    }
                })
            }),
            new Promise((resolve,reject)=>{
    
    
                $ajax({
    
    
                    url:'url2',
                    success:function(data){
    
    
                        resolve(data)
                    }
                })
            })
            // results为数组,分别保存从上到下的各个请求
        ]).then(results =>{
    
    
            // 这里是不能运行的,因为没有引用jq,因此并没有url,因此我们还是用settimeout来进行模拟

        })
    </script>

②用SetTimeout进行模拟

 Promise.all([
            new Promise((resolve,reject)=>{
    
    
                setTimeout(() => {
    
    
                    resolve({
    
    name:'yzk',age:20})
                }, 1000);
            }),
            new Promise((resolve,reject)=>{
    
    
                setTimeout(() => {
    
    
                    resolve({
    
    name:'Kobe',age:21})
                }, 2000);
            })
            
        ]).then(results =>{
    
    
            console.log(results);

        })

运行结果如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45664402/article/details/110849981