ES6的generator

generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次。

1、generator函数的定义是function*,这与普通函数是不同的

2、yield需使用在generator函数中,所表示的意思是“执行到这,并返回”

3、yield是有返回值的,其中value代表return的值,done代表函数是否执行结束。

yield 'your value'; // { value: 'your value', done: true }

yield; // { value: undefined, done: true }

generator跟函数很像,定义如下:

function* foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}

generator和函数不同的是,generator由function*定义(注意多出的*号),并且,除了return语句,还可以用yield返回多次。用处:可以编写一个产生斐波那契数列的函数:

function* fib(max) {
    var
        t,
        a = 0,
        b = 1,
        n = 0;
    while (n < max) {
        yield a;
        [a, b] = [b, a + b];
        n ++;
    }
    return;
}
fib(5)

直接调用一个generator和调用函数不一样,fib(5)仅仅是创建了一个generator对象,还没有去执行它,它只是返回一个遍历器对象(Iterator Object)。

调用generator对象有两个方法,一是不断地调用generator对象的next()方法:

var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true} 如果继续调用next方法,返回的也都是这个值

next()方法会执行generator的代码,然后,每次遇到yield x;就返回一个对象{value: x, done: true/false},然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。如果donetrue,则value就是return的返回值。当执行到donetrue时,这个generator对象就已经全部执行完毕,不要再继续调用next()了。

第二个方法是直接用for ... of循环迭代generator对象,这种方式不需要我们自己判断done

for (var x of fib(10)) {
    console.log(x); // 依次输出0, 1, 1, 2, 3, ...
}

yield 表达式如果用在另一个表达式中,必须放在圆括号里面:

{
  function* demo() {
    console.log('Hello' + yield); // SyntaxError
    console.log('Hello' + yield 123); // SyntaxError
  
    console.log('Hello' + (yield)); // OK
    console.log('Hello' + (yield 123)); // OK
  }
}

yield 表达式用作参数或放在赋值表达式的右边,可以不加括号:

{
  function* demo() {
    foo(yield 'a', yield 'b'); // OK
    let input = yield; // OK
  }
}

如果在 Generator 函数里面调用另一个 Generator 函数,默认情况下是没有效果的:

{
  function* foo() {
    yield 'aaa'
    yield 'bbb'
  }

  function* bar() {
    foo()
    yield 'ccc'
    yield 'ddd'
  }

  let iterator = bar()

  for(let value of iterator) {
    console.log(value)
  }

  // ccc
  // ddd

}

yield* 表达式用来在一个 Generator 函数里面 执行 另一个 Generator 函数:

{
  function* foo() {
    yield 'aaa'
    yield 'bbb'
  }

  function* bar() {
    yield* foo()      // 在bar函数中 **执行** foo函数
    yield 'ccc'
    yield 'ddd'
  }

  let iterator = bar()

  for(let value of iterator) {
    console.log(value)
  }

  // aaa
  // bbb
  // ccc
  // ddd
}

抽奖每抽一次提示一次剩余次数:

{
  // 具体抽奖逻辑的方法
  function draw(count) {
    // 执行一段抽奖逻辑
    // ...

    console.log(`剩余${count}次`)
  }

  // 执行抽奖的方法
  function* remain(count) {
    while(count > 0) {
      count--
      yield draw(count)
    }
  }

  let startDrawing = remain(6)

  let btn = document.createElement('button')
  btn.id = 'start'
  btn.textContent = '开始抽奖'
  document.body.appendChild(btn)

  document.getElementById('start').addEventListener('click', function(){
    startDrawing.next()
  }, false)
}

generator 函数实现轮询:

{
  // 请求的方法
  function* ajax() {
    yield new Promise((resolve, reject) => {
      // 此处用一个定时器来模拟请求数据的耗时,并约定当返回的json中code为0表示有新数据更新
      setTimeout(() => {
        resolve({code: 0})
      }, 200)
    })
  }

  // 长轮询的方法
  function update() {
    let promise = ajax().next().value    // 返回的对象的value属性是一个 Promise 实例对象
    promise.then(res => {
      if(res.code != 0) {
        setTimeout(() => {
          console.log('2秒后继续查询.....')
          update()
        }, 2000)
      } else{
        console.log(res)
      }
    })
  }

  update()
}

转载:https://www.liaoxuefeng.com/wiki/1022910821149312/1023024381818112

           https://my.oschina.net/pandon/blog/750333

           https://www.cnblogs.com/rogerwu/p/10764046.html

原文地址:https://www.cnblogs.com/xjy20170907/p/11414524.html