Generator.prototype.return()

1.Generator函数返回的遍历器对象还有一个return方法,可以返回给定的值,并终结Generator函数的遍历。

    function* gen(){
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next();// {value:1,done:false}
g.return("foo");//{value:foo,done:false}
g.next();//{value:undefined,done:false}
//上面的代码中,遍历器对象g调用return方法之后,返回的也是一个对象,而且这个对象的value属性就是return方法的参数foo.同时,Generator函数的遍历终止,返回值的done属性为true,以后再调用next方法,done属性总是返回true。如果return方法调用时不提供参数,则返回值的value属性为undefined。

2.如果Generator函数内部有try...finally代码块,那么return方法会推迟到finally代码块执行完再执行。

function* numbers(){
yield 1;
try{
yield 2;
yield 3;
}finally{
yield 4;
yield 5;
}
yield 6;
}
var g = numbers();
g.next(); //value:1
g.next();//value:2
g.return(7);//value:4
g.next();//value:5
g.next();//value:7

yield*语句

如果在Generator函数内部调用另一个Generator函数,默认情况下是没有效果的,必须要使用yield*语句

1.这个语句的作用:主要是用来在一个Generator函数中使用另一个Generator函数。

    function* foo(){
yield 'a';
yield 'b';
}
function* bar(){
yield 'x';
foo(); // 将这里修改成yield* foo(),就会有效果
yield 'y';
}
for(let v of bar()){
console.log(v);
}
//"x"
//"y"在这里面直接用yield语句是没有任何效果的

2.从语法角度看,如果yield命令后面跟的是一个遍历器对象,那么需要在yield命令后面加上星号,表明返回的是一个遍历器对象。这被称为yield*语句。

    let delegatedIterator = (function* (){
yield 'hello!';
yield 'bye!';
}()); let delegatingIterator = (function* (){
yield 'Greetings!';
yield* delegatedIterator;
yield 'ok,bye.';
}()) for(let value of delegatingIterator){
console.log(value);
} //"Greeting"
//"hello"
//"bye!"
//"ok,bye"

总结下来:(1)运行结果,就是使用一个遍历器遍历了多个Generator函数,有递归的效果。

(2)yield* 语句等同于在Generator函数内部部署一个for...of循环。

(3)yield* 语句后面还可以接数组,因为数组原生支持遍历器,因此会遍历数组成员

(4)yield* 语句后面,只要是有Iterator接口,都可以用yield*遍历。

3.如果被代理的Generator函数有return语句,那么可以向代理它的Generator函数返回数据。

    function* foo(){
yield 2;
yield 3
return "foo";
};
function* bar(){
yield 1;
var v = yield* foo();
console.log("v:" + v);
yield 4;
}
var it = bar();
it.next();//value:1
it.next();//value:2
it.next();//value:3
it.next();//"v:foo",value:4这里不是太明白,姑且认为是因为foo函数被bar()函数代理的缘故

4.yield*语句的一些比较常用的例子

(1)可以很方便的取出嵌套数组的所有成员

    function* iterTree(tree){
if(Array.isArray(tree)){ //判断是否是一个嵌套在数组内部的数组
for(let i=0;i<tree.length;i++){
yield* iterTree(tree[i]);//采用循环和递归的方法,来遍历出数组中的嵌套数组的成员
}
}else{
yield tree;
}
} const tree = ['a',['b','c'],['d','e']];
for(let x of iterTree(tree)){
console.log(x);
}
//a
//b
//c
//d
//e

(2)yield* 语句可以用来遍历完全二叉树

    //用构造函数构造一个完全二叉树
//3个参数分别是左子树,当前节点,右子树。
function Tree(left,label,right){
this.left = left;
this.label = label;
this.right = right;
} //下面是中序(inorder)遍历函数
//由于返回的是一个遍历器,所以要用Generator函数。
//函数体内采用递归算法,所以左子树和右子树要用yield*遍历。
function* inorder(t){
if(t){
yield* inorder(t.left);
yield t.label;
yield* inorder(t.right);
}
} //下面生成二叉树
function make(array){ //注意这个函数是一个普通函数
//判断是否是叶子节点
if(array.length == 1) return new Tree(null,array[0],null);
return new Tree(make(array[0]),array[1],make(array[2]));
} let tree = make([[['a'],'b',['c']],'d',[['e'],'f',['g']]]);
//var result = [];
for(let node of inorder(tree)){
//result.push(node);
console.log(node);
}

作为对象属性的Generator函数

1.如果一个对象的属性是一个Generator函数,则可以这样写:

    let obj = {
* myGeneratorMethod(){
...
}
}
//也可以这样写:
let obj = {
myGeneratorMethod:function* (){}
};

Generator函数的this

1.Generator函数总是返回一个遍历器,ES6规定这个遍历器是Generator函数的实例,它也继承了Generator函数的prototype对象上的方法。

2.如果只是把Generator函数当作普通的构造函数,并不会有任何效果,因为Generator函数返回的始终是遍历器对象,而不是this对象

function* g(){
this.a = 11;
}
let obj = g();
obj.a //undefined

3.还有如果使用new命令,这是不能生成F的实例,因为F返回的是一个内部指针。

function* F(){
yield this.x = 2;
yield this.y = 3;
}

上面的方法是没有任何效果的,想要把Generator函数当作正常的构造函数来使用,可以采用下面的变通方法。

    function* F(){
yield this.x = 2;
yield this.y = 3;
}
var obj = {};
var f = F.bind(obj)();//将obj和this绑定在一起。
//再次调用next方法
f.next();
f.next();
f.next();
obj //{x:2,y:3}

Generator函数推导

1.利用函数推导,可以进行惰性求值,如果需要将一个数组中的每个成员进行平方,如果用到函数推导,那么就只会在用到的时候,才会占用系统资源。

否则会先定义一个数组,这时候系统会被占用很大一部分资源。

    let generator = function* () {
for(let i=0;i<6;i++){
yield i;
}
}
let squared = ( for (n of generator()) n*n);
//等同于
//let squared = Array.from(generator()).map( n => n*n);
console.log(...squared);
//0 1 4 9 16 25

Generator函数推导是对数组结构的一种模拟,其最大的优点就是惰性求值,即直到真正用到的时候才会求值,这样可以保证效率。

含义

1.Generator与状态机

Generator函数很好的实现了两个或者两个状态以上的切换过程,而且是合作式的。

    var clock = function*(_){
while(true){
yield _;
console.log('Tick');
yield _;
console.log('Tock');
}
}

2.Generator与协程

传统的“子例程”采用堆栈式“后进先出”的执行方式,只有当调用的子函数完全执行完毕,才会结束执行父函数。协程与其不同,多个线程(单线程情况下即多个函数)可以并行执行,但只有一个线程(或函数)处于正在运行的状态,其他线程(或函数)都处于暂停态,线程(或函数)之间可以交换执行权。也就是说,一个线程(或函数)执行到一半,可以暂停执行,将执行权交给另一个线程(或函数),等到稍后收回执行权时再恢复执行。这种可以并行执行、交换执行权的线程(或函数),就称为协程。

从实现上看,在内存中子例程只使用一个栈,而协程是同时存在多个栈,但只有一个栈是在运行态。也就是说,协程是以多占用内存为代价实现多任务的并行运行。

3.协程与普通线程的差异

普通的线程是抢占式的,到底哪个线程优先得到资源,必须由运行环境决定,但是协程是合作式的,执行权由协程自己分配。而且Generator函数是ES6对协程的实现,但属于不完全实现。如果将Generator函数当作协程,完全可以将多个需要协作的任务写成Generator函数,他们之间用yield语句交换控制权。

Generator函数的主要应用

1.异步操作的同步化表达

例如:ajax操作,

function* main(){
var result = yield request("http:fff.url");//这里通过调用next方法来传递给result
var resp = JSON.parse(result);
console.log(resp.value);
} function request(url){
makeAjaxCall(url,function(response){
it.next(response);//将这个response传递给result,这里必须在next方法加上response参数,因为yield语句构成的表达式本身是没有值的,总是等于undefined。
})//这个函数主要是用来获取应答数据
}
var it = main();
it.next();

2.控制流管理:同步运行和异步运行

3.部署Iterator接口:利用Generator函数可以给任意对象部署Iterator接口,

function* iterEntries(obj){
let keys = object.keys(obj);
for(let i=0;i<keys.length;i++){
let key = keys[i];
yield [key,obj[key];//这里通过yield
}
}
let myObj = {foo:3,bar:7};
for(let [key,value] of iterEntries(myObj)){
console.log(key,value);//这里用for...of循环来遍历Generator函数
}

最后注意:

1.yield 语句后面可以接普通函数,也可以正常执行。

2.yield* 语句主要是用来在一个Generator函数中执行另一个Generator函数。主要可以实现递归。

Generator函数(三)的更多相关文章

  1. 转: ES6异步编程:Generator 函数的含义与用法

    转: ES6异步编程:Generator 函数的含义与用法 异步编程对 JavaScript 语言太重要.JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可. 以前,异步编程 ...

  2. Generator函数语法解析

    转载请注明出处: Generator函数语法解析 Generator函数是ES6提供的一种异步编程解决方案,语法与传统函数完全不同.以下会介绍一下Generator函数. 写下这篇文章的目的其实很简单 ...

  3. ES6的generator函数

    generator是什么? generator是ES6提供的一种异步编程解决方案,在语法上,可以把它理解为一个状态机,内部封装了多种状态.执行generator,会生成返回一个遍历器对象.返回的遍历器 ...

  4. ECMAScript 6 入门 ----Generator 函数

    本文转自:阮一峰老师的ECMAScript 6 入门,有时间可以看下评论! Generator 函数 简介 基本概念 Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不 ...

  5. 一次搞懂 Generator 函数

    1.什么是 Generator 函数 在Javascript中,一个函数一旦开始执行,就会运行到最后或遇到return时结束,运行期间不会有其它代码能够打断它,也不能从外部再传入值到函数体内 而Gen ...

  6. 前端笔记之ES678&Webpack&Babel(下)AMD|CMD规范&模块&webpack&Promise对象&Generator函数

    一.AMD和CMD规范(了解) 1.1传统的前端开发多个js文件的关系 yuan.js中定义了一个函数 function mianji(r){ return 3.14 * r * r } main.j ...

  7. ECMAScript 6 学习(一)generator函数

    1.ES2017标准引入async函数,那么async函数到底是个什么函数呢? async 是一个generator函数的语法糖. 2.那么generator函数到底是什么函数ne? generato ...

  8. JavaScript中的Generator函数

    1. 简介 Generator函数时ES6提供的一种异步编程解决方案.Generator语法行为和普通函数完全不同,我们可以把Generator理解为一个包含了多个内部状态的状态机. 执行Genera ...

  9. Generator函数执行器-co函数库源码解析

    一.co函数是什么 co 函数库是著名程序员 TJ Holowaychuk 于2013年6月发布的一个小工具,用于 Generator 函数的自动执行.短小精悍只有短短200余行,就可以免去手动编写G ...

随机推荐

  1. java===java基础学习(4)---字符串操作

    java中的字符串操作和python中的大致相同,需要熟悉的就是具体操作形式. 关于具体api的使用,详见:java===字符串常用API介绍(转) package testbotoo; public ...

  2. 2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6150 Vertex Cover 二分图,构造

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6150 题意:"最小点覆盖集"是个NP完全问题 有一个近似算法是说—每次选取度数最大 ...

  3. 手机端GPS定位结合百度地图实现定位

    html页面: <!DOCTYPE html>  <html>  <head>      <meta http-equiv="Content-Typ ...

  4. Context-Aware Network Embedding for Relation Modeling

    Context-Aware Network Embedding for Relation Modeling 论文:http://www.aclweb.org/anthology/P17-1158 创新 ...

  5. redis 的优化

    1.pipeling “请求-响应”模式的服务器在处理完一个请求后就开始处理下一个请求,不管客户端是否读取到前一个请求的响应结果.这让客户端不需要发一个请求等一个响应的串行,可以一次发送多个请求,再最 ...

  6. 欢迎访问新博客aiyoupass.com

    新博客基本搭建好了,欢迎访问.aiyoupass.com

  7. HDU 2829 Lawrence(四边形优化DP O(n^2))

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2829 题目大意:有一段铁路有n个站,每个站可以往其他站运送粮草,现在要炸掉m条路使得粮草补给最小,粮草 ...

  8. redis之(八)redis的有序集合类型的命令

    [一]增加元素 --->命令:ZADD key score member [score member] --->向有序集合放入一个分数为score的member元素 --->元素存在 ...

  9. hdu 1133(卡特兰数变形)

      题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1133   题意:排队买50块一张的票,初始票台没有零钱可找,有m个人持有50元,n人持有100元, ...

  10. hdu 2044-2050 递推专题

    总结一下做递推题的经验,一般都开成long long (别看项数少,随便就超了) 一般从第 i 项开始推其与前面项的关系(动态规划也是这样),而不是从第i 项推其与后面的项的关系. hdu2044:h ...