概念
通俗来讲,这就是异步编程的一种解决方案。
早期方式是通过回调,es6新增加了Promise,而Generator也是用于异步编程的,但更高级一点。
Generator包含多个步骤,每个步骤的标志就是yield或return。
遇到yield或return,就会停止运行。
进入下一步的时候,需要调用next( )。
使用方法
基本定义
生成器函数以function *
开头
返回值: Iterator结构数据
实例
//定义Generator
let tell = function* (){
yield 'a';
yield 'b';
return 'c';
};
let k = tell();
console.log(k.next()); // {value: 'a' , done:false}
console.log(k.next()); // {value: 'b' , done:false}
console.log(k.next()); // {value: 'c' , done:false}
console.log(k.next()); // {value: undefined , done:true}
Generator && Iterator
之前讲过Iterator,它有一个缺点,就是需要自己创建接口。
而如果使用Generator,我们可以就不创建接口了。
使用方法
1. 对象调用[Symbol.iterator]
2. 对象赋值给Generator
实例
let obj = {};
obj[Symbol.iterator]=function* (){
yield 1;
yield 2;
yield 3;
}
for(let value of obj){
console.log(value); // 1 2 3
}
状态机
当在yield外层加上while(1){}的时候,结果就会循环输出。
而且永远不会结束。
实例
let state = function* (){
while(1){
yield 'A';
yield 'B';
yield 'C';
}
}
let status = state();
console.log(status.next()); //{value: 'A' , done:false}
console.log(status.next()); //{value: 'B' , done:false}
console.log(status.next()); //{value: 'C' , done:false}
console.log(status.next()); //{value: 'A' , done:false}
console.log(status.next()); //{value: 'B' , done:false}
Async函数
与Generator相比,以async function
开头,yield替换成await
。
实例
改写上面的例子
let state = async function (){
while(1){
await 'A';
await 'B';
await 'C';
}
}
let status = state();
console.log(status.next());
console.log(status.next());
console.log(status.next());
console.log(status.next());
console.log(status.next());
Async是ES7新增的内容,在此暂不做过多介绍,有待以后补充。
使用实例
1)抽奖次数限制
let draw = function(count){
//具体抽奖逻辑
console.log(`剩余${count}次`)
}
//使用Generator控制次数
let res = function* (count){
//次数限制
while (count>0){
count--;
//执行抽奖逻辑
yield draw(count);
}
}
let star = res(5);
let btn = document.createElement('button');
btn.id = 'start';
btn.textContent='抽奖';
document.body.appendChild(btn);
document.getElementById('start').addEventListener('click',function(){
star.next();
},false)
运行结果
依次打印出 剩余4次
剩余3次
剩余2次
剩余1次
剩余0次
剩余0次以后,无法触发抽奖。
2)查询服务器状态
查询服务器状态可以使用轮询、Websocket等方式。
之前也有写了相关博文Web实时通讯——轮询、WebSocket
在这里,我们使用Generator写长轮询。
代码
//模拟ajax
let ajax =function* (){
yield new Promise(function(resolve,reject){
setTimeout(function(){
//↓↓模拟客服端返回的状态码
resolve({code:0})
},220);
})
}
let pull = function(){
//Generator实例化
let generator = ajax();
//让generator执行一次,也就是模拟通信一次
let step = generator.next();
//↓↓step.value是Promise实例
// ↓↓ ↓↓ function即是resolve,d即是参数集合
step.value.then(function(d){
//如果返回的code不是0,一秒后再次调用自身
if(d.code!=0){
setTimeout(function(){
console.log('wait');
pull()
},1000)
}
else{
console.log(d);
}
})
}
//调用
pull();