Generator函数的概述

Generator 函数是 ES6 提供的一种异步编程解决方案

Generator函数指的是一种新的语法结构,是一个遍历器对象生成器,它内部可以封装多个状态,很适合用于异步操作

Generator函数语法和普通的function函数类似,但是有三个不同点:

(1)function关键字和函数名称之间有一个星号(*)。

(2)函数体内可以使用yield语句。 可暂停函数(惰性求值), yield可暂停,next方法可启动。每次返回的是yield后的表达式结果

(3)函数调用后不会立即执行,返回的是一个遍历器对象

现实业务应用中,Generator的优点是可以等第一条请求发送成功之后,拿到数据在发送第二条请求,缺点是没有脱离回调函数

function* helloWorldGenerator() {
console.log('aaaaaaaaaa')
yield 'hello';
console.log('bbbbbbbbbb')
yield 'world';
console.log('ccccccccccc')
return 'ending';
} let hw = helloWorldGenerator();//调用此函数,并不会立即执行它其中的代码,而是返回一个遍历器对象 也就是指向内部状态的指针对象 // 必须调用遍历器对象的next方法,使得指针移向下一个状态。
// 也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。
// 换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。 // 第一次调用,Generator 函数开始执行,直到遇到第一个yield表达式为止。
// next方法返回一个对象,它的value属性就是当前yield表达式的值hello,done属性的值false,表示遍历还没有结束。
console.log(hw.next()) //{ value: 'hello', done: false }
console.log(hw.next()) //{ value: 'world', done: false }
console.log(hw.next()) //{ value: 'ending', done: true }
console.log(hw.next()) //{ value: undefined, done: true }
console.log(hw.next()) //{ value: undefined, done: true }

创建Generator函数

Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。

不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象

函数内部使用yield语句定义不同的状态,return也可以定义一个状态

每个yield语句定义不同的状态,它也是一个代码执行暂停标识,yield语句不能在普通函数中使用,否则会报错。

// 定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(hello和world)
// 即该函数有三个状态:hello,world 和 return 语句(结束执行)
function* helloWorldGenerator() {
console.log('aaaaaaaaaa')
yield 'hello';
console.log('bbbbbbbbbb')
yield 'world';
console.log('ccccccccccc')
return 'ending';
} let hw = helloWorldGenerator();//调用此函数,并不会立即执行它其中的代码,而是返回一个遍历器对象 也就是指向内部状态的指针对象 console.log(hw.next()) //{ value: 'hello', done: false },返回一个具有value和done属性的对象
console.log(hw.next()) //{ value: 'world', done: false }
console.log(hw.next()) //{ value: 'ending', done: true } ,有return,返回{value:ending,done:true}
console.log(hw.next()) //{ value: undefined, done: true },没有return,返回{value: undefined, done: true}
console.log(hw.next()) //{ value: undefined, done: true }

yield语句

每一个yield语句定义不同的状态,它也是一个代码执行暂停标识。

yield语句不能在普通函数中使用,否则会报错。

调用Generator函数可以返回一个遍历器对象,要想访问Generator函数中的每一个状态,需要使用遍历器对象调用next()方法

如果yield语句作为其他语句的一部分,那么必须使用小括号包裹,否则会报错

// 定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(hello和world)
// 即该函数有三个状态:hello,world 和 return 语句(结束执行)
function* helloWorldGenerator() {
//console.log("欢迎来到" + yield "generator");//报错,SyntaxError: Unexpected identifier
console.log("欢迎来到" + (yield "generator"));//正确,打印出:欢迎来到undefined
yield 'hello';
return 'ending';
} let hw = helloWorldGenerator();//调用此函数,并不会立即执行它其中的代码,而是返回一个遍历器对象 也就是指向内部状态的指针对象 console.log(hw.next().value) //generator
console.log(hw.next().value) //hello
console.log(hw.next().value) //ending

next()方法

next()一个主要功能,就是从暂停状态继续下一段代码的执行。

next()还有一个重要的功能,那就是可以接受一个参数,此参数作为上一个yield语句的返回值。

虽然当代码执行到yield语句的时候,能够将其后面的表达式的值作为对象的value属性值,但是默认情况下yield语句是没有返回值的,或者说它的返回值是undefined

function* helloWorldGenerator() {
console.log("欢迎来到" + (yield "generatoraaaaaa"));
console.log("欢迎来到" + (yield "generatorbbbbbb"));
yield 'hello';
return 'ending';
} let hw = helloWorldGenerator(); console.log(hw.next('我是注入进来的aaaa')) //第1个next传值无意义,因为没有上一个yield
console.log(hw.next('我是注入进来的bbbb'))
console.log(hw.next('我是注入进来的cccc'))
console.log(hw.next())

function* yuanku(num) {
let x = 2 * (yield num);
console.log('x='+x);
let y = yield x*3;
console.log('y='+y);
console.log(x,y);
}
var g = yuanku(5);
console.log(g.next());//{value:5,done:false},第1个next传值无意义,因为没有上一个yield
console.log(g.next());//x=NaN {value:NaN,done:false}
console.log(g.next(3));//{value:12,done:false}
console.log(g.next(3));//{value:undefined,done:true}

Generator 函数应用——部署Iterable接口

普通的对象在部署iterable接口之前,是不能使用for of去遍历对象的

  let obj = {
userName: 'huang',
age: 32
}
for (let i in obj){ // for in可以遍历普通对象的属性
console.log(i)
} for (let i of obj) { // for of不能遍历普通对象的属性 报错:obj is not iterator
console.log(i)
}

核心思想:可以将任何数据作为Generator函数的参数,当我们调用Generator函数返回的Generator类实例对象就可以认为是参数的遍历器对象,且这个遍历器对象上还有Symbol.iterator属性方法,方法的返回值指向遍历器对象自己

  let obj = {
userName: 'huang',
age: 32
} //相当于给obj这个对象人为的部署了iterator,之后就可以使用for of进行遍历内部的状态
obj[Symbol.iterator] = function* myGenerator () {
yield 1
yield 2
yield 3
} for (let i of obj) {
console.log(i) //遍历了myGenerator函数的状态,默认就是调用next方法,分别是1,2,3
}
function* deployObjectInterface(obj){
let keys = Object.keys(obj);
console.log(keys)
for(let i=0; i<keys.length; i++){
let key = keys[i];
yield [key, obj[key]];
}
}
let obj = {name:"Cynthia", age:21 };
for(let[key, value] of deployObjectInterface(obj)){
console.log(key, value);
}
// name Cynthia
// age 21

Generator 函数应用——部署Ajax操作

模拟一个业务逻辑,首先发送一次请求,成功之后拿到请求回来的数据,再发送第二次请求(这次请求需要用到第一次请求回来的数据)

如果第一条请求没有成功,第二次请求不会触发

function getNews(url) {
$.get(url, function (data) {
console.log(data)
let url = 'http://sss:3000?id='+ data.id
SX.next(url) //第二次请求
})
} function* sendXml() {
yield getNews('http://sss:3000')
yield getNews(url)
}
let SX = sendXml()
SX.next() // 第一次请求

ES5-ES6-ES7_Generator 函数的更多相关文章

  1. es6的箭头函数和es5的function函数区别

    一.es6的箭头函数es6箭头函数内部没有this,使用时会上朔寻找最近的this不可以做构造函数,不能使用new命令,因为没有this函数体内没有arguments,可以使用rest参数代替不能用y ...

  2. 简述ES5 ES6

    很久前的某一天,一位大神问我,你知道ES6相对于ES5有什么改进吗? 我一脸懵逼的反问,那个啥,啥是ES5.ES6啊. 不得不承认与大神之间的差距,回来深思了这个问题,结合以前的知识,算是有了点眉目. ...

  3. es6箭头函数讲解

    es6箭头函数的用法 箭头函数是es6的一种函数的简写方法. 如下: var f = v = > v; //等同于 var f = function(v){ return v; } var su ...

  4. es6箭头函数 this 指向问题

    es5中 this 的指向 var factory = function(){ this.a = 'a'; this.b = 'b'; this.c = { a:'a+', b:function(){ ...

  5. Atitit js es5 es6新特性 attilax总结

    Atitit js es5 es6新特性 attilax总结 1.1. JavaScript发展时间轴:1 1.2. 以下是ES6排名前十的最佳特性列表(排名不分先后):1 1.3. Es6 支持情况 ...

  6. ES6 箭头函数 this 指向

    ES6 箭头函数 this 指向 箭头函数有几个使用注意点: 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象. 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个 ...

  7. 深入理解ES6之函数

    一:关于函数的参数: 可以接受任意数量的参数而无视函数声明的参数数量是js函数的独特之处. 1:参数默认值 ES6之前做法: function makeRequest(url,timeout,call ...

  8. ES6入门——函数的扩展

    1.函数参数的默认值 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法.现在ES6可以为函数的参数添加默认值,简洁了许多. ES5 function show(a,b){ b = b ...

  9. es6之函数扩展与对象扩展

    一.函数扩展 1.参数默认值 参数有默认值,后面不可以再加没有默认值的变量.如以下test函数中,不可以加写成 function test(x,y="word",z){ } fun ...

  10. 【转】React Native中ES5 ES6写法对照

    很多React Native的初学者都被ES6的问题迷惑:各路大神都建议我们直接学习ES6的语法(class Foo extends React.Component),然而网上搜到的很多教程和例子都是 ...

随机推荐

  1. [Linux] Linux的环境变量

    环境变量可以被系统,用户,shell以及其他程序来设定 登录系统后,系统读取/etc/profile 文件,设置环境变量,如果没有就跳过 检查主目录(/root)的.profile文件,推荐去这个文件 ...

  2. Dev、GridControl的模糊查询

    /// <summary> /// 设置girid为每一列都模糊搜索 /// </summary> /// <param name="gdv"> ...

  3. CPU 实用工具

    系统版本:CentOS 7.4 top 17:49:04 // 当前时间 up 3:55 // 系统运行时间,格式为时:分 2 users // 当前登录用户数 load average // 三个值 ...

  4. JS中的柯里化(currying)

    何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名). 柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参 ...

  5. 《JavaScript高级程序设计》笔记:基本概念(三)

    数据类型 ECMAScript中有5种简单数据类型(也称为基本数据类型):undefined,null,boolean,number和string. typeof typeof null会返回“obj ...

  6. python中经典类和新式类的区别

    要知道经典类和新式类的区别,首先要掌握类的继承.类的继承的一个优点就是减少代码,而且使代码看起来结构很完整. 那什么是经典类,什么是新式类呢? 经典类和新式类的主要区别就是类的继承的方式 ,经典类遵循 ...

  7. 详解Vue.js 技术

    本文主要从8个章节详解vue技术揭秘,小编觉得挺有用的,分享给大家. 为了把 Vue.js 的源码讲明白,课程设计成由浅入深,分为核心.编译.扩展.生态四个方面去讲,并拆成了八个章节,如下: 准备工作 ...

  8. 【代码笔记】Web-JavaScript-javaScript for循环

    一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  9. Apache Beam WordCount编程实战及源码解读

    概述:Apache Beam WordCount编程实战及源码解读,并通过intellij IDEA和terminal两种方式调试运行WordCount程序,Apache Beam对大数据的批处理和流 ...

  10. Testlink1.9.17使用方法(第十二章 总结)

    第十二章 总结 QQ交流群:585499566 TestLink用于进行测试过程中的管理,通过使用TestLink提供的功能,我们可以将测试过程从:测试需求.测试设计.到测试执行.完整的管理起来,同时 ...