用ES7解决异步回调地狱问题

用了 Promise 其实并没有真正解决回调地狱问题,并且还新增了很多 .then(data => { .... }) 这些很没有意义的 “模板代码”。所以先人们又搞出了generator 和 async/await,generator 有一些很神奇的特性这个就不多说了,自己看 MDN 上的文档就好,但是 generator 也能挺方便地处理异步。

一、promise+迭代器=生成器

首先我们需要了解什么是迭代器( iterator),迭代就是指提供了统一的遍历复杂数据类型的方案。我们先回忆一下在内置对象中自带遍历器的有哪些?

  • Array
  • Set
  • Map
  • String
  • NodeList
  • 函数:arguments

使用迭代器的语法有(ES6):

  • for-of
  • ... 扩展运算符
        function forOf(arr,deal){
            //拿到迭代器函数
            let iteratorFn = arr[Symbol.iterator];
            //迭代器函数调用得到迭代器,(注意保护内部this指向)
            let it = iteratorFn.call(arr);
            // console.log(it.next());//next方法调用得到“结果对象”,结果对象有两个属性:value 当前遍历到的元素,done 指示遍历完成的标志(值为true/false)
            let resultObj;
            while (!(resultObj = it.next()).done) {
                console.log(resultObj.value);
            }
        }
        forOf(arr,function(v){
            console.log(v);

        })

再来看看生成器:

  1. function* genFn(){},生成器函数:function*
  2. let gen = genFn();,调用生成器函数 得到生成器
  3. gen.next(),生成器函数的next方法,将生成器函数进行分段调用

补充:

  • 结果对象,next()方法调用,不仅使函数分段调用了,还得到一个结果对象,包含value属性和done属性
  • yield,生成器函数分段的关键字,后面可以跟一个value值,就是结果对象的value值
        //生成器函数:function* yield   也可认为分段函数 
        function* genFn() {
            console.log(1111);
            yield 444;
            console.log(2222);
            yield 555;
            console.log(3333);

        }
        // //调用生成器函数 得到生成器
        let gen = genFn();
        console.log(gen.next());
        console.log(gen.next());
        console.log(gen.next());
        let resultObj;
        while (!(resultObj = gen.next()).done) {
            console.log(resultObj.value);
        }

 

可以将yield看作分段,生成器函数中的的代码根据fn.next()调用次数来执行,调用几次则执行几段代码

二、ES7方法

1、关键字:

  • async:“所有”函数都可以加上async关键字变成一个异步函数;
  • await:只能使用在异步函数中,用来等待promise操作的promise.value

2、内容

  • 异步函数执行的结果是一个Promise对象,该对象受到函数返回值的影响,具体参照Promise.resolve(value)
  • 异步函数中的await关键字是有运算结果的,结果是一个Ptomise对象,该对象受到await后面的表达式影响,具体参照Promise.resolve(value)

现在有一个任务,有A,B,C,D四个步骤,其中D函数可以异步的得到一个结果,就是A函数想要的结果,怎么才能使A获得该结果?

思路:A---->B B---->C C---->D

首先我用比较粗暴的方法——回调函数来实现

        function a(){
            b(function(data){
               console.log(data);
            })
        }
        function b(cd_b){
            c(function(data){
               cd_b(data)
            })
        }
        function c(cd_c){
            d(function(data){
               cd_c(data)
            })
        }
        function d(cd_d){
            setTimeout(()=>{
                let data = "彩虹"
                cd_d(data)
            },2000)
        }
        a();

这种回调需要将每一次传参的弄个清楚,非常麻烦,而且很容易让人包括自己阅读起来昏头,所以不建议使用这种方法,那么如果我们使用ES7的方法是否能简化代码,使其语义化增强呢?

        async function A() {
           console.log(await B());
        }

        async function B() {
            return await C();
        }

        async function C() {
            return await D();
        }

        async function D() {
            return await new Promise((resolve) => {
                setTimeout(() => {
                    let data = "彩虹"
                    resolve(data);
                }, 3000)
            })
        }

        A();

可以看到,我们只需要将返回值获取,调用最顶层的函数就可以了,语义化比回调函数强上很多,也不存在传参混乱的问题了,这是一个非常方便的方法。

posted @ 2019-12-15 22:26  袁钧钧  阅读(352)  评论(0编辑  收藏  举报