Generator 函数是 ES6 提供的一种异步编程解决方案,也是遍历器生成函数,语法行为与传统函数完全不同。
1 基本用法
使用function关键字后加*
的方式声明一个函数,该函数即为Generator函数
let tell = function* (){
yield 1;
yield 2;
yield 3;
}
let k = tell();
console.log(k.next());//{value: 1, done: false}
console.log(k.next());//{value: 2, done: false}
console.log(k.next());//{value: 3, done: false}
console.log(k.next());//{value: undefined, done: true}
由上面代码可知,Generator函数有多个返回值状态(每个yield关键字后跟一个状态),只有调用next()函数时才会返回值,每调用一次next()函数就返回一个对象{value: xxx, done: false}
,直到没有对应的yield了就返回done状态为true的对象{value: undefined, done: true}
。
2 添加遍历器
一个普通的对象obj默认是没有遍历器的,意味着不能使用for...of遍历,且不能使用...
操作符解构。
let obj = {
name:'zhangsan',
age:18,
sex:'man'
}
for(var value of obj){
console.log(value);//报错 obj is not iterable
}
console.log([...obj]);//报错 obj is not iterable
可见都是报错obj is not iterable
,我们通过Generator函数给其添加遍历器。
let obj = {
name:'zhangsan',
age:18,
sex:'man'
}
obj[Symbol.iterator]=function* (){
for(var key in obj){
yield obj[key];
}
}
for(let value of obj){
console.log(value);//zhangsan 18 man
}
console.log([...obj]);//["zhangsan", 18, "man"]
3 将ajax请求转成类似的 let a = ajax()的同步赋值形式
经常碰见一个业务内多个请求串联依赖,即后者依赖前者的请求结果,目前只能有两种做法,
- 回调函数嵌套
- 使用promise的
.then
进行链式调用
但现在我们学习了Generator函数后可以有第三种选择 - 将前一个网络请求的返回值赋值给一个变量,在下一个请求中使用
即以下形式:
let a = 请求1(){}
let b = 请求2(a){}
实现代码如下:
let res = 0;
//封装一个网络请求函数,不做实际动作,就打印一下参数param
function ajaxMy(method,url,param,varibal){
console.log(param);
//使用延时计时器模拟网络请求1秒后返回正确结果response
setTimeout(function(){
let response = res++;
varibal.next(response);
},300)
}
let k;
let tell = function* (){
//网络请求1
let a = yield ajaxMy('get','www.baidu.com',10,k);
console.log(a);//0
//网络请求2
let b = yield ajaxMy('get','www.baidu.com',a,k);
console.log(b);//1
//网络请求3
let c = yield ajaxMy('get','www.baidu.com',b,k);
console.log(c);//2
//网络请求4
let d = yield ajaxMy('get','www.baidu.com',c,k);
console.log(d);//3
}
k = tell()
k.next();
以上代码let a = yield ajaxMy('get','www.baidu.com',10,k);
类似于将一个网络请求的返回值赋值给了a
变量,可在下一步请求yield ajaxMy('get','www.baidu.com',a,k);
中作为参数使用,这样一来编写业务逻辑就会清晰很多。
4 实现状态机
let state = function* (){
while(1){
yield 'block';
yield 'none';
}
}
let displayClass = state();
console.log(displayClass.next().value);//block
console.log(displayClass.next().value);//none
console.log(displayClass.next().value);//block
console.log(displayClass.next().value);//none
每调用一次next,value值会在block,none
两值之中来回切换,且不会被篡改。
5 实现轮询
//请求方法,返回值包括状态码和数据
let requestSingFn = function* (){
yield new Promise(function(resolve,reject){
setTimeout(function(){
resolve({code:304,data:{username:'zhangsan'}});
},300)
})
}
//轮询函数 只有当code为200时才会停止发送请求
let requestFn = function(){
let req = requestSingFn();
let stat = req.next();
stat.value.then(function(response){
if(response.code!=200){
setTimeout(function(){
console.log('重新发送请求');
requestFn();
},1000);
}else{
console.log(response.data);
}
})
}
requestFn();
async函数的优势:
1、不用通过执行器去触发程序往下走
2、参数传递特别方便,await会等待后续promise函数执行完成,将结果取出,才接着往下走。
function promise1(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(16)
},1000)
})
}
function promise2(){
let var1 = await promise1();//确定是否登陆
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(160)
},1000)
})
}
async function myasyncFn(){
let var1 = await promise1();//确定是否登陆
console.log(var1,'-------')
let var2 = await promise2();//如果已经登陆,去请求数据
console.log(var2)
return var2
}
let myreturn = myasyncFn()
myreturn.then((res)=>{
//用户利用最终返回值去完成自己的业务逻辑
console.log(res,'最终返回值')
})
只有当code的状态变为200成功响应才会停止发送请求,否则每个1300毫秒发送一次请求
ES6总篇--目录
网友评论