一、Generator生成器函数
Generator函数是ES2015提出的异步的解决方案,与普通的函数有很大的不同;
生成器提供了一种【中断机制】,使得子程序可以暂时返回,等在之后的某个时刻,继续回来运行。
特点:
(1)generator函数与普通函数不同,普通函数一旦调用就会执行完,但是generator函数中间可以暂停,执行一会歇一会。
(2)在function关键字后面跟一个(*)号;
(3)在函数体内部使用yield表达式作为一个状态,实现暂停;
(4)generator函数执行并不会有什么效果,而是返回一个迭代器对象,之后调用迭代器的next方法会返回一个值对象。
举例说明:
function *go(a){ console.log(1); //yield语句只是标识符,并没有返回值 //yield左边等于next()传来的参数值,没传参则为undefined,yield右边是next()的返回值 let b=yield a; console.log(2); let c=yield b; console.log(3); return c; } let iterator=go('aaa'); let r1=iterator.next();//第一次next()不用传参 console.log(r1);// 1 {value: "aaa", done: false} let r2=iterator.next('bbb'); console.log(r2);//2 {value: "bbb", done: false} let r3=iterator.next(); console.log(r3);//3 {value: undefined, done: true} done属性值代表当前迭代是否完成。 //例2 function *gen(x){ var y=2*(yield (x+1)); var z=yield (y/3); return x+y+z; } var t=gen(5); console.log(t.next());//{value: 6, done: false} console.log(t.next(12));//{value: 8, done: false} console.log(t.next(13));//{value: 42, done: true} //解析:yield (x+1)表达式将传递值6到外部,在第二次调用next(12)的时候,传递12到generator函数内部作为yield(x+1)表达式的值,因此y被赋值12*12=24.接下来,下一条yield(y/3) 将向外传值值8.第三次调用next(13)传递13到generator函数内部给yield(y/3),所以z的值为13
在生成器中的return值:便利返回对象的done值为true时迭代即结束,不会对该value处理。
function *createIterator() { yield 1; return 42; yield 2; } let iterator1 = createIterator(); console.log(...iterator); // 1
async是Generator函数的语法糖。async的实现原理就是将Generator函数和自动执行器包装在一个函数里。
相比于generator,Async函数有以下几点改进:
(1)内置执行器。generator函数的执行必须依赖执行器,而async函数自带执行器,调用的方式和普通函数的调用一样。
(2)返回值是promise对象。比起generator函数返回的iterator对象更加方便,可以直接使用then()方法调用。
二、Iterator迭代器
迭代器是一种特殊的对象,它具有一些专门为迭代过程设计的接口,所有的迭代器对象都有一个next()方法,每次调用都返回一个结果对象。该结果对象有两个属性:value(表示下一个将要返回的值)和done(布尔值,表示迭代过程是否结束)
手动实现一个简单的迭代器
测试数据:
三、可迭代对象
1、可迭代对象具有Symbol.iterator属性,是一种与迭代器密切相关的对象。
在ES6中所有集合对象(Array、Set结构和Map结构)和String都是可迭代对象,这些对象都有默认的迭代器。
ES6中新加入的特性for of循环需要用到可迭代对象这些功能。
for-of循环每执行一次都会调用可迭代对象的next()方法,并将迭代器返回的结果对象的value属性存储在一个变量中,循环将持续执行这一过程直到返回对象的done属性值为true。
通过生成器创建的迭代器也是可迭代对象,因为生成器默认会为Symbol.iterator属性赋值。
2、判断一个数据是否具有可迭代能力,只有当数据具有Symbol.iterator属性的时候才可以使用for-of进行迭代。
3、默认迭代器
ES6为很多内置对象提供了默认的迭代器,只有当内建的迭代器不能满足需求时才自己创建迭代器。
S6的三个集合对象:Set、Map、Array都有默认的迭代器,常用的如values()方法、entries()方法、keys()方法都返回一个迭代器。其值区别如下:
- entries():多个键值对
- values():集合的值
- keys():集合的键
var obj={ a:1, b:2, c:3 } for(let item of obj){ console.log(item)//Uncaught TypeError: obj is not iterable } for(let item of Object.keys(obj)){ console.log(item)//a,b,c } for(let item of Object.values(obj)){ console.log(item)//1,2,3 }
我们可以通过Symbol.iterator属性来访问可迭代对象的默认迭代器。例如对一个数组:
思考:
1、既然数组等具有可迭代能力,但是为什么我们直接用arr.next()或报错?
是因为可迭代对象不代表是一个迭代器,只有迭代器才具有next()方法。所以具有可迭代能力的对象,如果想要使用next()方法,必须先转换为迭代器。
可迭代对象不一定是迭代器,但是迭代器一定是可迭代对象。
co模块?
用于generator函数的自动执行。是我们可以不用编写generator函数的执行器。
co模块其实是将两种自动执行器(thunk函数和promise对象)包装成一个模块,然后返回的是promise对象。