ES5-ES6-ES7_Generator 函数

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() // 第一次请求
原文地址:https://www.cnblogs.com/LO-ME/p/10594026.html