语法
个人理解:Generator是一个代码生成器,每次调用,生成一块代码。
特征:
- function和函数名之间有一个*
- 函数体内是用yield关键词(return表示结束)
方法:
- next()
- throw()
- return()
一个简单的demo
function* Gen () {
yield 'Hello';
yield 'Generator';
return '!';
}
let gen = new Gen();
console.log(gen.next()); // Hello
console.log(gen.next()); // Generator
console.log(gen.next()); // !
或者可以这样访问
for (let g of Gen()) {
console.log(g)
}
next参数的问题
next中可以添加一个参数,作为下一个yield或者return的参数
function* Gen () {
let a = 1;
let b = 2;
let c = yield a + b;
let d = yield c - a;
return d;
}
let gen = new Gen();
let g1 = gen.next();
console.log(g1.value); // 3
let g2 = gen.next(g1);
console.log(g2.value); // 2
let g3 = gen.next(g3);
console.log(g3.value); // 2
yield* 语句
在Generator中直接调用另一个Generator函数是不会起作用的,需要使用yield*语句,起作用相当于将两个Generator合并
function* Gen() {
yield 'start';
yield* test();
yield 'end';
}
function* test () {
yield 'test1';
yield 'test2';
}
for (let g of Gen()) {
console.log(g);
}
// 输出结果
// start
// test1
// test2
// end
应用
基本的应用场景大概有两类
1. 流程控制(一搬用作UI上的loading)
2. 状态机(通过传入flag来控制)
结合Promise实现简单的co
简单的介绍一下co的实现
其实就是一个迭代器,检测到未执行完毕就再执行一次,如果执行完毕的话就调用resolve,中途出现错误的情况就调用reject。
需要注意的地方就两个,一个是将前一个next返回的结果传入到下一个next当做参数,另一个是讲一切非Peomise对象转化为Peomise对象
在上一篇记录中曾用Promise对ajax进行封装,配合上co,可以发挥更大的威力
// co.js
export default function (Gen) {
return new Promise(function (resolve, reject) {
let gen = new Gen();
next(data) => {
let current = data ? gen.next(data) : gen.next();
current.value = current.value instanceof Promise ? current.value : Promise.resolve(current.value);
if(!current.done) {
current.value
.then(_data = > next(_data))
.catch(error => reject(new Error(error)))
} else {
resolve(current.value);
}
}
})
}
// test.js
import $co from './co';
$co(function* () {
let a = 1;
let b = 2;
let c = yield a + b;
let d = yield c - a;
return d;
})
.then(message => console.log(message))
.catch(error => console.error(error))