ES6 - Generator

2019-08-15  本文已影响0人  明里人

generator(生成器)是ES6标准引入的新的数据类型,与函数类似,但它可以返回多次。
generator由 function * 定义,并且除了使用return,还可以通过定义 yield 返回多次。
generator不像普通函数一样,调用就会执行,需要通过next()方法执行:

function* helloGenerator() {
  console.log('this is generator');
}
var h = helloGenerator(); // 这里调用不会执行console
h.next(); // 执行console
例子:

要编写一个斐波那契数列的函数:

function fib(max) {
  var t, a = 0, b = 1, arr = [0, 1];
  while (arr.length < max) {
    [a, b] = [b, a + b];
    arr.push(b);
  }
  return arr;
}
console.log(fib(5)); // [0, 1, 1, 2, 3]

函数只能返回一次,使用generator,可以实现返回多次结果。

function* fib(max) {
  var t, a = 0, b = 1, arr = [0, 1];
  while (arr.length < max) {
    [a, b] = [b, a + b];
    arr.push(b);
    yield arr;
  }
  if (max === 2) {
    return arr
  }
 }

fib() 仅仅创建了一个generator对象,还没有去执行它。
执行generator有两种方式:
1、next() 方法:

var fun = fib(5);
console.log(fun.next()); // {value: Array(3), done: false}
console.log(fun.next()); // {value: Array(4), done: false}
console.log(fun.next()); // {value: Array(5), done: false}
console.log(fun.next()); // {value: undefined, done: true}

next() 方法会执行generator代码,每次遇到 yield,就会返回一个对象 {value: x, done: true / false}。value 就是 yield 的返回值,done为true时,表示这个generator已经全部执行完毕。
2、for ... of循环迭代generator对象

for (var arr of fib(5)) {
    console.log(arr)
}
// (3) [0, 1, 1]
// (4) [0, 1, 1, 2]
// (5) [0, 1, 1, 2, 3]

这种方式没有返回值done,会自动判断可执行的yield。

解决回调地狱,异步代码按同步执行:
function prepare(success) {
    setTimeout(function() {
        console.log('prepare');
        success(); // 执行成功后再执行下一个next()方法
    },500)
}
function fired(success) {
    setTimeout(function() {
        console.log('fired');
        success(); // 执行成功后再执行下一个next()方法
    },500)
}
function stewed(success) {
    setTimeout(function() {
        console.log('stewed');
        success(); // 执行成功后再执行下一个next()方法
    },500)
}
function sdd(success) {
    setTimeout(function() {
        console.log('sdd');
        success(); // 执行成功后再执行下一个next()方法
    },500)
}
function serve(success) {
    setTimeout(function() {
        console.log('serve');
        success(); // 执行成功后再执行下一个next()方法,此时返回结果done为true
    },500)
}
function* task() {
    yield prepare;
    yield fired;
    yield stewed;
    yield sdd;
    yield serve;
}
function run(fn) {
    const gen = fn();
    function next() {
        const result = gen.next();
        if (result.done) return;
        
        result.value(next);
    }
    next();
}
run(task);
// 执行结果:
// prepare
// fired
// stewed
// sdd
// serve
上一篇 下一篇

猜你喜欢

热点阅读