什么是Generator
你可以理解为一个状态队列,遇到执行指令next时再调用yield参数。
function* gen() {
console.log('step 1:');
yield '1';
console.log('step 2:');
yield '2';
console.log('step 3:');
return '3';
console.log('step 4:');
}
var g=gen();
console.log(g.next());
console.log(g.next());
console.log(g.next());
console.log(g.next());
执行结果:
"step 1:"
Object {
done: false,
value: "1"
}
"step 2:"
Object {
done: false,
value: "2"
}
"step 3:"
Object {
done: true,
value: "3"
}
Object {
done: true,
value: undefined
}
可以看到gen的实例执行next()方法,每遇到yield就执行一次并且挂起,直到下一个next()。 直到最后一个yield执行完,下一次执行next()返回{done:true,value:3}。如果再次执行next()则返回{done:true,value:undefined}。
这样就实现了类似于异步线程的同步:想象一下,原来是这些异步函数各自独立执行,执行时间未知,现在是必须一条一条执行完。
yield 后面可以跟返回值,也可以是执行语句。
yield console.log(3+2);
注意
- Generator函数使用的是自执行函数,而不是new实例化,否则会报错;
- yield必须只能在Generator内使用,否则报错。
yield*
yield* 相当于执行另一个Generator的引用,类似于include。
// yield*
function* a(){
yield 'a';
}
function* b(){
yield 'b';
yield* a();
yield 'c';
}
var B=b();
console.log(B.next());
console.log(B.next());
console.log(B.next());
console.log(B.next());
结果:
{value: "b", done: false}
{value: "a", done: false}
{value: "c", done: false}
VM196:1 {value: undefined, done: true}
使用场景
- 异步操作的同步化
function workflow(){
showLoadingSplash();
yield loadData();
hideLoadingSplash();
}
var loader=workflow();
loader.next();//加载UI
load.next();//卸载UI
- 控制流程
如果是一个多步操作,使用回调函数的写法如下:
step1(function(value1){
step2(function(value2){
step3(function(value3){
//
}
}
}
Promise的写法:
Promise.resolve(step1)
.then(step2)
.then(step3)
.then(function(value3){
//resolved
},function(error){
//reject
})
Generator写法:
function *workflow(value1){
try{
var value2 = yield step1(value1);
var value3 = yield step1(value2);
var value4 = yield step1(value3);
}catch(e){
}
}
function scheduler(task){
var taskObj=task.next(task.value);
if(!taskObj.done){
task.value=taskObj.value;
scheduler(task);
}
}
scheduler(workflow(initialValue));
- 实例遍历Iterator接口
function* iterEntries(obj){
let keys=Object.keys(obj);
let key=null;
for(let i=0,len=keys.length;i<len;i++){
key=keys[i];
yield [key, obj[key]];
}
}
let entity={name:'Migao',id:'walkingp'};
for(const [key,value] of iterEntries(entity)){
console.log(`${key}: ${value}`);
}
结果:
"name: Migao"
"id: walkingp"