ES6语法——Generator

Generator
基本概念
  • 异步编程的一种解决方案
  • 异步的编程方式:回调(早期的异步编程方式)、Promise、Generator
  • Generator相对Promise更高级些
  • next和yield*都是Generator内的一部分
  • Generator里包含多个步骤,它遇到哪个步骤,哪个步骤的标志就是yield或者是return,它遇到yield或者return就停止了,这和普通的函数有很大的区别
  • Generator要进行下一步的时候,就调用next函数去进行下一步,直到结束
next函数的用法
yield*的语法
{
	//generator基本定义
	let tell = function* (){//function后面有个*//tell可以理解为是Generator函数
	//函数体有 yield语句
		yield 'a';
		yield 'b';
		return 'c';
	}
	//以上就是Generator定义的基本方式
	let k = tell();//函数的执行都是圆括号()
	console.log(k.next());//通过next()不断的执行函数体的每个阶段
	console.log(k.next());
	console.log(k.next());
	console.log(k.next());
	//{value: "a", done: false}
	//{value: "b", done: false}
	//{value: "c", done: true}
	//{value: undefined, done: true}
	//Generator函数返回的就是一个Iterator接口		
	//通过next()的方式不断的去做函数体的几个阶段
	//也就是说,在执行tell()的时候,它会在遇到第一个yield的时候,停下来,执行完yield之前的语句(这个demo中没有写yield之前的语句),等你调用next()的时候,它会执行第一个yield,当你调用第二个next(),它会执行接下来的一个yield或者return,以此类推,从而保证这个函数体内部看上去是一个异步操作的过程,这就是Generator的基本用法
	
}

Generator函数与Iterator接口的关系
  • 因为任意一个对象的Iterator接口都是部署在Symbol.iterator属性上
  • Generator函数就是一个遍历器生成函数,所以呢,我们可以直接把它赋值给Symbol.iterator ,从而使这个对象也具有Iterator接口
  • Iterator接口手动自定义,现在补充一种方式:Generator也可以作为遍历器的返回值
{
	//定义一个空对象,对象没有Iterator接口,不能使用for...of
	let obj = {}//要使用for...of必须手动部署一个Interator接口
	//通过创建Genarator函数的方式给obj部署Interator接口
	obj[Symbol.iterator]=function* (){
		yield 1;
		yield 2;
		yield 3;
	}
	//以上是Generator新的应用,也是Generator与Interator的关系
	//相对于手动部署,Generator方法简洁很多
	for(let value of obj){
		console.log('value',value)
		//1
		//2
		//3
	}
	//以上,先 生成一个空对象,然后通过Generator函数生成三个步骤,然后通过for...of遍历到三个值,这是Generator新的应用
}
Generator应用场景和优势
  • 状态机(js编程中,状态机是比较高级的用法)
    比如说,用三种状态描述一个事物,
    这个事物只存在三种状态,A=>B,B=>C,C=>A;三个之间循环永远跑步出第四种状态出来,使用Generator处理这种状态机,是特别适用的
{
	let state = function* (){
		while(1){//while(1)循环,永远在这个步骤里
			yield 'A';
			yield 'B';
			yield 'C';
		}
	}
	let status = state();
	console.log(status.next());
	console.log(status.next());
	console.log(status.next());
	console.log(status.next());
	console.log(status.next());
	//{value: "A", done: false}
	//{value: "B", done: false}
	//{value: "C", done: false}
	//{value: "A", done: false}
	//{value: "B", done: false}
	//这样就一直循环下去
}
//async await 语法的写法
//asyc await 是 Generator的语法糖
//asyc await 并不是异步编程方式,而是Generator的语法糖
//执行asyc await 语法,需要按照babel的一些插件
{
	let state =async function (){
		while(1){//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());
	//{value: "A", done: false}
	//{value: "B", done: false}
	//{value: "C", done: false}
	//{value: "A", done: false}
	//{value: "B", done: false}
	
}

Generator应用场景——抽奖

当前账户下,用户还可以抽奖5次
用户点击一次,抽奖变成4,3,…
抽奖剩余次数的逻辑,前端要做限制,服务端也要做限制

//前端做抽奖剩余次数的限制
{
	//抽奖业务这块(即抽奖逻辑)
	let draw = function(count){//draw函数实现当前的逻辑和剩余次数的显示
		//具体抽奖逻辑(不写,根据具体业务自行完成)
		//输出剩余次数
		console.info(`剩余${count}次`)
	}
	//怎么去计算还剩多少次呢?
	//之前的做法可能是设置一个全局的变量来保存当前的次数
	//设置全局变量是非常不安全的,会被修改变量的风险,少把存储数据放在全局变量上,这会影响页面性能的
	//如何使用Generator处理这个业务?
	let residue=function* (count){//通过Generator控制次数
		while (count>0) {//while对次数的限制
			count--;
			yield draw(count);//yield执行具体的抽奖逻辑
		}
	}
	//Generator实例化
	//通过按钮绑定起来
	//每点击一次执行一次next(),next就是抽奖,当次数用完以后,再怎么点,抽奖逻辑也不会有反应
	let star = residue(5);//5应该是服务端传递给前端的一个数
	let btn=document.createElement('button')
	btn.id='start';
	btn.textContent='抽奖';
	document.body.appendChild(btn);
	document.getElementById('start').addEventListener('click',function(){
		star.next();
	},false)
//使用Generator好处是,次数没有保存在全局变量中
}
Generator应用场景——长轮询
  • 长轮询:比如说服务端的某一个数据状态,定期的去变化,前端需要定时的去服务端取这个状态,因为HTTP是无状态的连接;
  • 如何取得服务端实时的变化呢,长轮询和websocket两种方式
  • 因为websocket浏览器兼容性不好,所以长轮询还是普遍的用法
  • 长轮询普遍做法是通过定时器不断的访问这个接口;
  • 现在使用Generator完成长轮询同时区分业务相关逻辑
//长轮询、模拟ajax过程
{
	//对接口的模拟
	let ajax = function* (){
		yield new Promise(function(resolve,reject){
			setTimeout(function(){
				resolve({code:1})
			},2000);
		})
	}
	//轮询的过程
	let pull = function(){
		let generator=ajax();//Generator实例化
		let step = generator.next();//取得generator的步骤
		//generator.next() 这个使yield运行一次,获取Promise实例,Promise实例是对服务端接口连接查询一次;
		step.value.then(function(d){//这个step.value就是Promise实例
		//d就是从服务端拿回的数据(即{code:0})
			if(d.code != 0){//判断数据拿到的是不是最新的,如果不是就再请求
				setTimeout(function(){
					console.info('wait')
					pull()
				},1000);	
			}else{//如果拿到最新数据长轮询查询结束
				console.info(d);
			}
		})
	}
	pull();//这个步骤,相当于执行了一次轮询
}
//以上通过Generator与Promise结合,简化长轮询
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值