(1)Generator 与状态机
Generator 是实现状态机的最佳结构,每运行一次,就改变一次状态。Generator 之所以可以不用外部变量保存状态,是因为它本身就包含了一个状态信息,即目前是否处于暂停态。
var clock = function* (){
while(true){
console.log('Tick');
yield;
console.log('Tock');
yield;
}
}
(2)异步操作的同步化表达
Generator 函数的暂停执行的效果,意味着可以把异步操作写在 yield 表达式里面,等到调用 next 方法时再往后执行。这实际上等同于不需要写回调函数,因为异步操作的后续操作可以放在 yield 表达式下面,反正要等到调用 next 方法时再执行。所以,Generator 函数的一个重要实际意义就是来处理异步操作,改写回调函数。
fnnction* numbers(){
let file = new FileReader("numbers.txt");
try{
while(!file.eof){
yield parseInt(file.readLine(), 10);
} finally {
file.close();
}
}
}
上面代码,打开文件,使用 yield 表达式可以手动逐行读取文件。
(3)控制流管理
如果有一个多步操作非常耗时,采用回调函数,可能会写成下面这样:
step1( function(value1){
step2(value1, function(value2){
step3(value2, function(value3){
// 操作
});
});
});
采用 Promise 改写上面的代码。
Promise.resolve(step1)
.then(step2)
.then(step3)
.then(function (value3){
// 操作
})
.done();
使用 Generator 函数改写。
function* runningRask(value1){
try{
var value2 = yield step1(value1);
var value3 = yield step2(value2);
var value4 = yield step3(value3);
// 操作
} catch (e){}
}
利用 for...of
循环会自动执行 yield 命令特性,提供一种更一般的控制流管理的方法。
let steps = [step1Func, step2Func, step3Func];
function* iterateSteps(steps){
for(var i = 0; i < steps.length; i++){
var step = step[i];
yield step();
}
}
for(var step of iterateSteps(steps)){}
注意:上面的做法只能用于所有步骤都是同步操作的情况,不能有异步操作的步骤。
(4)部署 Iterator 接口
利用 Generator 函数,可以在任意对象上面部署 Iterator 接口。
function* iterEntries(obj) {
let keys = Object.keys(obj);
for (let i=0; i < keys.length; i++) {
let key = keys[i];
yield [key, obj[key]];
}
}
let myObj = { foo: 3, bar: 7 };
for (let [key, value] of iterEntries(myObj)) {
console.log(key, value);
}
// foo 3
// bar 7
(5)作为数组结构
Generator 可以看作是数组结构,更确切地是,可以看作是一个数组结构,因为 Generator 函数可以返回一系列的值,这意味着它可以对任意表达式,提供类似数组的接口。