最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • [ JavaScript ] 对于 Promie 和 async/await 的理解和使用

    正文概述 掘金(GavinUI)   2021-03-10   507

    对 promise 和 async/await 的理解

    promise 是 es6 新增的异步解决方案。虽然, promise 可以解决回掉地狱的问题,但是,如果出现大量的异步请求或者比较复杂的情况下其实也会出现很多的 then ,稍微对 promise 的微任务注册不是理解的特别清晰就会出错。 所以, es7 的 async/await 就是解决这样的一个问题。

    Pomise 基本的使用方法

    delayDoAjax(interval){
        return new Promise((resolve, reject) => {
            if (typeof interval !== 'number') return reject(new Error('数据格式有误'));
            setTimeout(() => {
                resolve(`延迟了 ${interval} 后输出`)
            }, interval)
        });
    };
    // running
    console.log(
        this.delayDoAjax(100)
            .then(res => { console.log(res); return this.delayDoAjax(1000) })
            .then(res => console.log(res))
            .catch(err => console.log(err))
    );
      // output
      //我延迟了100毫秒后输出的
      //我延迟了1000毫秒后输出的
    

    在执行 resolve 的时候,pomise 的状态就被改变继续向下执行 then ,catch 可以输出错误问题。其中,后面的 then 采用了链式调用的方法。 catch 虽然是放在了最后面,但是,catch 的错误捕获是针对整一个链式调用的,只要其中的一环出现了错误,catch 都能捕获到错误信息。

    Promise 微任务

    以下面一段代码为例 :

    new Promise((resolve, reject) => {
        resolve('ok')
    }).then(res => {
        console.log(`status: ${res}`);
    });
    

    new Promise(...).then , 就是同步执行任务,而 then 其中的函数体就是注册到进微任务队列中。 Promise 中的微任务还有 catch 和 finally,就是 Promise 涉及状态变更后需要被执行的回掉才算是微任务。

    在多种注册微任务和调用情况下的分析

    promise 中 return 新建的 promise

    new Promise((resolve, reject) => {
        console.log('promise-1')
        resolve();
    })
        .then(res => {
            console.log("promise-1-then-1");
            return new Promise((resolve) => {
                console.log("promise-2");
                resolve();
            })
                .then(res => {
                    console.log("promise-2-then-1");
                })
                .then(res => {
                    console.log("promise-2-then-2");
                });
        })
        .then(res => {
            console.log("promise-1-then-2");
        });
    

    这一段代码,里面的 promise 是使用 return 的形式,那么,第一个 promise 的第二个 then 就需要等里面的那个 promise 执行完毕,才会执行 第一个promise 的第二个 then 。

    promise 中直接新建 promise

    new Promise((resolve) => {
        console.log('promise-1');
        resolve();
    })
        .then(res => {
            console.log('promise-1-then-1');
            new Promise((resolve) => {
                console.log('promise-2')
                resolve();
            })
                .then(res => {
                    console.log('promise-2-then-1')
                })
                .then(res => {
                    console.log('promise-2-then-2')
                })
                .then(res => {
                    console.log('promise-2-then-3')
                })
        })
        .then(res => {
            console.log('promise-1-then-2')
        })
        .then(res => {
            console.log('promise-1-then-3')
        })
    

    由于,外部的第二个 then 的注册,需要等外部的第一个 then 的同步代码执行完毕。所以,在内部的promise 执行完毕,且注册了第一个 then 的时候,外部的同步方法已经执行完毕,这个之后注册了 外部的第二个 then。这时执行了 内部的第二个 then,同时也会注册内部的第三个 then,微任务队列这时会执行 promise-1-then-2 ,所以看起来就是交替的注册和执行,最终的结果如下:

    // promise-1
    // promise-1-then-1
    // promise-2
    // promise-2-then-1
    // promise-1-then-2
    // promise-2-then-2
    // promise-1-then-3
    // promise-2-then-3
    

    定义一个 promise 对象

    new Promise((resolve, reject) => {
        console.log('promise-1')
        resolve();
    }).then((res) => {
        console.log('promise-1-then-1');
        const response = new Promise((resolve, reject) => {
            resolve();
        });
        response.then(res => {
            console.log('promise-2-then-1');
        });
        response.then(res => {
            console.log('promise-2-then-2');
        })
    })
        .then(res => {
            console.log('promise-1-then-2')
        })
    

    由于内部的 then 时同步是通过 response 这个 promise 对象调用的,所以,在这里内部的两个 then 可以说是同时注册 ,当内部的 then 依次执行完毕之后,才会执行外部的 then。 执行的结果如下:

    // promise-1
    // promise-1-then-1
    // promise-2-then-1
    // promise-2-then-2
    // promise-1-then-2
    

    定一个 promise 对象,同时 这个 promise 对象里面还有一个 promise

    const response = new Promise((resolve, reject) => {
        console.log("promise-1");
        resolve();
    });
    response.then(res => {
        new Promise((resolve, reject) => {
            console.log("promise-2");
            resolve();
        })
            .then(res => {
                console.log("promise-2-then-1");
            })
            .then(res => {
                console.log("promise-2-then-2");
            })
            .then(res => {
                console.log("promise-2-then-3");
            });
    });
    response.then(res => {
        console.log("promise-1-then-2");
    });
    response.then(res => {
        console.log("promise-1-then-3");
    });
    

    首先,第一个 promise 有 3 个 then,都是通过 promise 对象执行为同步事件,执行了第一个then 内部的 pomise 之后,内部的第一个 then 同步事件执行完毕,就会执行第一个 promise 的 2和3的then,执行完毕之后再执行微任务队列的 内部promise 第一个 then ,再依次执行。 执行结果如下:

    // promise-1
    // promise-2
    // promise-1-then-2
    // promise-1-then-3
    // promise-2-then-1
    // promise-2-then-2
    // promise-2-then-3
    

    含有直接创建的 promise 和 return 的 promise

    new Promise((resolve, reject) => {
        console.log("promise-1");
        resolve();
    })
        .then((res) => {
            console.log("promise-then-1");
            new Promise((resolve, reject) => {
                resolve();
            })
                .then((res) => {
                    console.log("promise-2-then-1");
                })
                .then((res) => {
                    console.log("promise-2-then-2");
                });
            return new Promise((resolve, reject) => {
                console.log("promise-3");
                resolve();
            })
                .then((res) => {
                    console.log("promise-3-then-1");
                })
                .then((res) => {
                    console.log("promise-3-then-2");
                });
        })
        .then((res) => {
            console.log("promise-1-then-2");
        });
    

    这里,首相执行同步函数,一开始就会依次建立好 3个 promise 对象,当第二个 promise 被创建时候,第二个 promise 的第一个 then 会注册进微任务队列,第三个 promise 的第一个 then 也会加入到微任务的队列中,之后再一次执行微任务队列的方法同时又会再注册对应的下一个then和执行,最终的效果看起来也是交替进行,结果如下:

    // promise-1
    // promise-1-then-1
    // promise-2
    // promise-3
    // promise-2-then-1
    // promise-3-then-1
    // promise-2-then-2
    // promise-3-then-2
    // promise-1-then-2
    

    async/await 的基本使用

    const response = async () => {
        const result = await new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('1000');
                console.log('await')
            }, 1000)
        });
        console.log('debugger');
        return result;
    }
    response().then(res => {
        console.log('res:', result);
    })
    

    async 和 await 大多数情况是同时出现的,async 放在 function 前面 是表示这个是一个异步函数,同时,这个函数返回的就是一个promise 对象。 await 意思就是 等待,等待注册的 then 函数体异步返回,在没有收到返回值的情况下,他是不会继续向下执行的。 以上面的例子来说, 输出的顺序一定依次是 await debugger res:1000 。

    async/await 之循环遍历执行

    async function ajax(time) {
        return new Promise((reslove, reject) => {
            setTimeout(() => {
                reslove(time);
                console.log(time)
            }, time);
        })
    }
    const arr = [1000, 3000, 2000];
    for (const doc of arr) {
        await ajax(doc);
    }
    

    async/await 使用案例分析

    依次请求和接收结果的情况

    实现需求是 请求 loadData1 拿到参数再请求 loadData2 再拿参数。

    例(1):错误写法

    (async () => {
        function ajax(url) {
            console.log("start: " + url);
            return new Promise((resolve) => {
                setTimeout(() => {
                    resolve(1000);
                }, 1000);
            });
        }
        // 第一次 发送请求
        ajax("loadData1").then((result1) => {
            console.log("result1:", result1);
        });
        // 第二次 发送请求
        const result2 = await ajax("loadData2");
        console.log("result2:", result2);
    })();
    

    这样的写法就会有问题,在执行 ajax("loadData1") 的时候,then 是注册进微任务队列之后异步函数处理,这个时候,then 不会执行而是,注册进微任务队列,然后函数直接再向下执行,执行了 ajax("loadData2");,这样子输出的结果就是 :

    // start: loadData1
    // start: loadData2
    // result1: 1000 
    // result2: 1000 
    

    很明显这样就是不对的, 应该两个都是 使用 await ,每一个请求方法的执行 都要等待上一个接口的数据返回,代码如下:

    例(1):正确写法

    (async () => {
        function ajax(url) {
            console.log("start: " + url);
            return new Promise((resolve) => {
                setTimeout(() => {
                    resolve(1000);
                }, 1000);
            });
        }
        // 第一次 请求
        const result1 = await ajax("loadData1");
        console.log("result1:", result1);
        // 第二次 请求
        const result2 = await ajax("loadData2");
        console.log("result2:", result2);
    })();
    

    这样 ,ajax("loadData2") 的执行,必须等待 result1 有结果才会 执行 ,代码如下:

    // start: loadData1
    // result1: 1000 
    // start: loadData2
    // result2: 1000 
    

    例(2):错误写法

    // methods
    async ajax(name, time){
        return new Promise((reslove, reject) => {
            setTimeout(() => {
                reslove(time);
                console.log(name);
            }, time);
        })
    }
    // mounted
    this.ajax('loadData1', 2000)
    this.ajax('loadData2', 1000)
    

    这里的打印结果不是 loadData1 再 loadData2,而是反过来。因为,上下两段 this.ajax 是并列执行的,所以,两个函数的返回植不会依顺序到达,而是谁先回来就输出对应的 name 。

    例(2): 正确写法

    把上面的例子稍微改下, 在 this.ajax 前面加上 await ,接可以了

    async ajax(name, time){
        return new Promise((reslove, reject) => {
            setTimeout(() => {
                reslove(time);
                console.log(name);
            }, time);
        })
    }
    // mounted
    async mounted(){
        await this.ajax('loadData1', 2000)
        await this.ajax('loadData2', 1000)
    }
    

    运动模式 + 音乐 = 咖啡;感觉今天要吃超速罚单了.......


    起源地下载网 » [ JavaScript ] 对于 Promie 和 async/await 的理解和使用

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元