Iterator、Generator、async、await基本语法

嘚嘚两句

天气非常燥热,心情也异常的烦躁。真的是想要暴躁啊。

Iterator接口

数组具有Iterator接口,其本质是有Symbol.iterator属性

        let arr = [1, 3, 5];
        let iter = arr[Symbol.iterator]();
        console.log(iter);

iter返回的是一个遍历器接口,有next方法。
在这里插入图片描述
Iterator是遍历器,for of语句的本质就是遍历器。实现Iterator接口的对象就是可遍历的,如果没有这个接口,就不能遍历。Iterator的内部实现本质是指针对象。调用next方法,移动指针指向对象中的下一个属性成员。
下面给出官方的解释:

Iterator 的遍历过程是这样的:
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。

每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。

next方法的使用
		console.log(iter.next());
        console.log(iter.next());
        console.log(iter.next());
        console.log(iter.next());

执行第一个next方法时,接口内部的指针指向数组的第一个成员 1 ,得到value值,成员 1 后面还有数组成员,所以done属性为false。再次执行next方法,指针指向 3 ,遍历未结束;接着调用next,指向 5 未结束遍历;最后一次next指针指向5的后一位,值未undefined,此时遍历结束,done值为true。
在这里插入图片描述

类数组对象String的原生Iterator接口

string类型也实现了Iterator接口。本来字符串就可以通过for of循环遍历出字符的。

        let str = 'hello';
        console.log([...str]);

在这里插入图片描述

Generator函数

Generator的作用是同Promise的作用一样,都是处理异步操作,但是Generator比Promise又好用点,结构更加清晰。Generator主要的应用场景是在请求的过程中存在业务逻辑的判断,根据判断的不同做不同的操作。
Generator的两个作用:返回Iterator遍历器对象;状态机。

Generator语法

在function关键字后面加上 * 就是一个Generator,yield是同Generator函数配套使用的,Generator状态机的实现就是通过yield实现的。

        function* funName(){
            yield 表达式,
            yield 表达式,
            ......
        }

简单的小栗子:

        function* generatorFun() {
            yield 123;
            yield 234;
            return "ending";
        }
        let gen = generatorFun();
        console.log(gen);

定义了Generator函数generatorFun,内部有两个yield表达式,123和234,所以该函数有三个状态:123、234和return语句。

next方法

Generator函数也是函数,调用同样是使用一对() ,不过Generator函数调用之后不执行,而是返回一个Iterator遍历器对象,必须使用next方法调用下一个状态。
代码的执行遇到yield暂停,调用next方法使得遍历器内部指针对象从函数头部或者上次停止得位置开始执行,直到遇到下一个yield。简言之就是,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行

使用next执行:

        function* generatorFun() {
            console.log("开始执行");
            yield 123;
            console.log("第一个yield执行完毕");
            yield 234;
            console.log("第二个yield执行完毕");
            return "ending";
            console.log("return");
        }
        let gen = generatorFun();
        console.log(gen.next()); //{value: 123, done: false}
        console.log(gen.next()); //{value: 234, done: false}
        console.log(gen.next()); //{value: ending, done: true}
        console.log(gen.next()); // {value:undefined,done:true}

执行第一个next时,输出 ” 开始执行 “,遇到yield停止,同时把yield后面得表达式得值存入当前成员得value中123;第二次调用next,输出文字,遇到第二个yield停止,取得表达式的值234;第三次调用next, 返回ending,函数结束。return语句后面的语句不执行。
在这里插入图片描述

next方法中的参数

调用next方法时传递参数,传递参数会赋值给上一个yield的处理结果。
先来个例子:

        function* generator() {
            let a = 2 * (yield 1);
            let b = yield(a * 10);
            return a + b;
        };
        let gen = generator();
        console.log(gen.next()); // {value:1,done:false}
        console.log(gen.next()); // {value:NaN,done:false}
        console.log(gen.next()); // {value:NaN,done:true}

我们想要的结果是 a = 2,b = 20,但是在第二次调用next方法时,value值为NaN。这是为什么?因为 next取得的是 a * 10,上一次yield的返回值为1,存入value,但是 yield 1 整体的值返回的是undefined,a = yield 1 结果为NaN,2 undefined 为NaN,同样 undefined10也是NaN,最后return同样为NaN。
在这里插入图片描述
如果想要让a = 2,就得往next方法中传递参数

        let gen2 = generator();
        console.log(gen2.next()); // {value:1,done:false}
        // next中的参数是上一个yeild表达式的返回值 设置yield 1 返回值为1
        console.log(gen2.next(1)); // {value:20,done:false}
        // 设置上一次yield(a*20) 返回值为 20
        console.log(gen2.next(20)); // {value:22,done:true}

这样就得到理想结果了。
在这里插入图片描述
整个过程分为三个阶段:
阶段1:yield 1
阶段2:设置上一次yield返回值为1,赋值a,并执行 yield (a*10)
阶段3:设置上一次yield返回值为20,赋值b,返回 a+b
我画图来解释一下:
在这里插入图片描述

yield*

当一个Generator内部调用另一个Generator函数时,就需要用到yield*。
上面也说l,运行Generator函数会产生一个Iterator遍历器对象,

        function* gen2() {
            yield "gen211";
            yield "gen210";
            return "gen230";
        }

        function* generator() {
            yield 11;
            yield "22";
            yield gen2(); // 遍历出来的是一个遍历器对象
            return 33;
        };
        let gen = generator();
        for (const value of gen) {
            console.log(value); //return直接返回 不会被遍历出来
        }

yield 后 放Generator函数,遍历得出的是遍历器函数。
在这里插入图片描述

	yield* gen2(); // 遍历出来的是一个遍历器对象的值

yield* 会自动遍历的gen2函数
在这里插入图片描述
gen2函数有返回值,在generator中也是会接收到的,定义一个变量

        function* generator() {
            yield 11;
            yield "22";
            // yield gen2(); // 遍历出来的是一个遍历器对象
            // yield* gen2(); // 遍历出来的是一个遍历器对象的值
            let result = yield* gen2(); // 遍历出遍历器对象的值,并接收遍历器的return值 
            console.log("gen2中return值:" + result);
            return 33;
        };
        let gen = generator();
        for (const value of gen) {
            console.log(value); //return直接返回 不会被遍历出来
        }

在这里插入图片描述

async和await

async、await是Promise的语法糖,使用同步的代码,实现异步操作。

async语法

async 函数
async function 异步函数 返回的是一个Promise对象
只有这个Promise对象的状态改变之后才能调用后续then中的回调函数。

        // 1.
        async function myDate() {
            // 里面的异步操作完成后才会执行then方法的回调函数
            return 1;
        }
        // 2.
        let async1 = async function () {
            // return 2;
            throw new Error("error!!!!")
        }
        // 3.
        let async2 = async () => {
            return 3;
        }
        let p = myDate();
        console.log(p); // 返回Promise对象
        p.then(value => console.log(value)); // 返回值作为then方法中回调函数的参数

在这里插入图片描述

await语法

await 表达式
注意点:

  1. await必须在async函数中,在普通函数中使用报错
  2. await表达式结果一般是Promise对象成功状态的返回结果
  3. await后面的表达式也可不是Promise对象,直接返回普通表达式的值
  4. try catch块捕获 await 中可能出现的错误

简单使用:

        function sleep(interval) {
            return new Promise(resolve => {
                setTimeout(resolve, interval);
            })
        }
        async function FiveInAsync() {
            await sleep(5000);
            // 休眠5秒接着输出
            console.log(1111);
        }
        let time = FiveInAsync();

当await后面不是Promise对象时:

        async function myDate() {
            // await 2;
            let res = await 2;
            console.log(res);
            return 1;
        }
        let p = myDate();
        console.log(p);

直接返回表达式的值
在这里插入图片描述
使用try catch捕获错误:使用try catch捕获await可能出现的错误,如果不做处理的话,在出错的地方之后的代码是不会执行的。

        async function myDate() {
            try {
            // 其他很多异步代码 ......
                await Promise.reject("error");
            } catch (error) {
                console.log(error); // 捕获await后面Promise对象rejected状态的错误信息
            }
            let res = await Promise.resolve("right");
            console.log(res);

        }
        let p = myDate();
串并行问题

正常来说,一个await成功返回后,才会执行下一步,如果第一个await返回时间较长的话,下一个await必须等待本次await返回完成才会执行,这叫串行,按照顺序执行。
串行代码:

        function asyncFunByOne() {
            return Promise.resolve("异步1");
        }

        function asyncFunByTow() {
            return Promise.resolve("异步2");
        }
        async function asyncFun() {
            // a 和 b 会先后执行
            // await asyncFunByOne() 执行返回后,asyncFunByTow()才会执行
            let a = await asyncFunByOne();
            let b = await asyncFunByTow();
            console.log(a, b);
        }
        let p = asyncFun();

并行的话就是多个await可以同时触发,不需要等待。
并行代码:

        function asyncFunByOne() {
            return Promise.resolve("异步1");
        }

        function asyncFunByTow() {
            return Promise.resolve("异步2");
        }
        async function asyncFun() {
            // 两个await同时执行 a1 b1同时触发
            let a = asyncFunByOne();
            let b = asyncFunByTow();
            let a1 = await a;
            let b1 = await b;
            console.log(a1, b1);

        }
        let p = asyncFun();

其实并行的话,Promise.all方法也能实现,这个方法必须得等到所以Promise实例对象成功之后才返回。

热得我心情非常烦躁,暂时先写到这吧,看文档也就了解了这些基础知识,具体的案例实例都没写呢还。
坚持就是胜利,告诉自己不燥不燥,你可以的!!!
哈哈哈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值