es6-generator

104 阅读2分钟

generator函数

generator函数又称生成器函数;

  • 它是es6的一种异步解决方案;
  • 内部可以封装多个状态, 因此又可以理解为是一个状态机。
  • 调用 Generator 函数,返回的是一个指向内部状态的指针对象,也就是遍历器对象(Iterator);

Generator 函数是分段执行的, yield 表达式是暂停执行的标记,而 next 方法可以恢复执行。调用next 方法,就会返回一个有着 value 和 done 两个属性的对象。 value 属性表示当前的内部状态的值,是 yield 表达式后面那个表达式的值; done 属性是一个布尔值,表示是否遍历结束。

function *gen() {
    console.log(1)
    yield 'a'
    console.log(2)
    yield 'b'
    console.log(3)
}
let g = gen()
let res1 = g.next() // 1
console.log(res1) // { value: 'a', done: false }
let res2 = g.next() //2
console.log(res2) // { value: 'b', done: false }
let res3 = g.next() //3
console.log(res3) //{ value: undefined, done: true }

next方法参数

yield表达式本身没有返回值,或者说总是返回 undefined 。 next 方法可以带一个参数,该参数就会被当作上一个 yield 表达式的返回值。

function *gen() {
    console.log(1)
    let a = yield 'a'
    console.log(2, a)
    let b = yield 'b'
    console.log(3, b)
}
let g = gen()
let res1 = g.next('AAA') // 1
console.log(res1) // { value: 'a', done: false }
let res2 = g.next('BBB') //2 "BBB"
console.log(res2) // { value: 'b', done: false }
let res3 = g.next('CCC') //3 "CCC"
console.log(res3) //{ value: undefined, done: true }

可以看到next()第一次传的参数没有用;那是因为 next 方法的参数表示上一个 yield 表达式的返回值,所以在第一次使用 next 方法时,传递参数是无效的

generator可快速部署可迭代对象

function* foo() {
  yield 1;
  yield 2;
  yield 3;
}
 
for (let i of foo()) {
  console.log(i);
}
// 1 2 3

generator异步代码处理

   function ajax() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                resolve("数据");
            }, 1000);
        });
    }

    function* gen() {
        yield ajax();
        yield ajax();
    }

    let g = gen();
    g.next().value.then(function(res) {
        console.log(res, 1);
        return g.next().value;
    }).then(function(res) {
        console.log(res, 2);
        return g.next().value;
    })

上述代码和使用promise代码类似,可解决回调地域。将代码进行改进,可变成一个自动执行的执行器。如下:

function autoRun(gen) {
    let g = gen();
    function next(data) {
        let res = g.next(data)
        if(res.done) return;
        res.value.then(
            function(data) {
                next(data)
            }
        )
    }
    next()
}

只要 Generator 函数还没执行到最后一步,next函数就会一直调用自身,以此实现自动执行。通过使用生成器配合执行器,就能实现使用同步的方式写出异步代码了。这也是asyc…await的实现原理;async内置执行器,返回的是一个promise

//对比执行器和aynsc...await写法
function* gen() {
    yield ajax();
    yield ajax();
}
autoRun(gen)

const gen = async ()=> {
    await ajax()
    await ajax()
}