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()
}