代码改变世界

Generator yield语法和 co模块

2018-04-12 11:21  muamaker  阅读(490)  评论(0编辑  收藏  举报

Generator  yield 语法使用,也叫生成器,实际上就是多个异步按顺序执行

function* gen(){
    //第一步 开始
    console.log("start");
    var a =  yield "aaa";
     
    //第二步
    console.log("---",a); //2
    var x = yield 222;
     
    //第三步
    console.log("---",x);//3
    var y = yield 4;
     
    //第四步
    console.log("---",y);//6
    
    return "over"
}
var g = gen(); //任何东西都没有执行,返回的一个迭代器, 可以使用 for  of  遍历
 
 
// next 的传值是上一段  yield 的返回值
 
console.log(g.next(1));
console.log(g.next(2));
console.log(g.next(3));
console.log(g.next(6));

  

可以看到,上面最后的调用,是可以封装成递归的,免得重复代码,多层嵌套,比如自己写一个,自运行的

  

const promisify = require("util").promisify;
const fs = require("fs");
const readFile = promisify(fs.readFile);
const path = require("path");
function resolve(p){
	return path.resolve(__dirname,p);
}

function* gen(){
	var data1 = yield readFile(resolve("./data/data1.json"),"utf-8");
	console.log(data1);
	var data2 = yield readFile(resolve("./data/data2.json"),"utf-8");
	console.log(data2);
	
	var num = yield 123456;
	
	console.log(num);
}



//简单版自运行co模块
function co(gen){
	var g = gen(); //任何东西都没有执行,返回的一个迭代器
	function next(res){
		var result = g.next(res);
		if(!result.done){
			Promise.resolve(result.value).then((res)=>{
				next(res); 
			}).catch((e)=>{
				throw new Error(e);
			})
		}
	}
	next();
}

co(gen);

  

 

或者使用co模块

const fs = require('fs');
const co =require('co');
const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, "utf-8",function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};

const gen = function* () {
  const f1 = yield readFile('./data1.txt');
  const f2 = yield readFile('./data2.txt');
  console.log(f1);
  console.log(f2);
};

co(gen).then(function(data){
	
	console.log(data);
	
}).catch(function(ct){
	
	console.log(ct);
	
})

  

 

Yield * 表达式

如果在 Generator 函数内部,调用另一个 Generator 函数。需要在前者的函数体内部,自己手动完成遍历。

function* foo() {
  yield 'a';
  yield 'b';
}

function* bar() {
  yield 'x';
  // 手动遍历 foo()
  for (let i of foo()) {
    console.log(i);
  }
  yield 'y';
}

for (let v of bar()){
  console.log(v);
}

  

ES6 提供了yield*表达式,作为解决办法,用来在一个 Generator 函数里面执行另一个 Generator 函数。

function* bar() {
  yield 'x';
  yield* foo();
  yield 'y';
}

  

flat 数组

	function * flat(arr){
		for(let i = 0 ; i < arr.length; i++){
			if(Array.isArray(arr[i])){
				yield *flat(arr[i])
			}else{
				yield arr[i];
			}
		}
	}
	
	const gen = flat([1,2,3,[3,4],8]);

	for(let item of gen){
		console.log(item)
	}

  

 

模拟任务调度器 

	class Schedule{
		constructor(arg) {
			this.low_priority = [];
			this.high_priority = [];
		}
		addLowTask(task){
			this.low_priority.push(task);
		}
		addHighTask(task){
			this.high_priority.push(task);
		}
		execute(p){
			// 其实就是 co 的顺序执行
			let g = this.runLow(p);
			function next(res){
				var result = g.next(res);
				if(!result.done){
					Promise.resolve(result.value).then((res)=>{
						next(res);
					}).catch((e)=>{
						throw new Error(e);
					})
				}
			}
			next();
		}
		run(p){
			this.execute(p);
		}
		*  runLow(p){
			let task;
			// 任务调度
			while(task = this.low_priority.shift()){
				if(this.high_priority.length > 0){
					// 存在优先级高的任务
					// 当前任务被挂起等待
					yield * this.runHigh();
				}
				p = yield task(p);
			}
		}
		* runHigh (p){
			let task;
			while(task = this.high_priority.shift()){
				p = yield task(p);
			}
		}
	}
	
	
	function create(data , time=1){
		return ()=>{
			return new Promise((resolve,reject)=>{
				setTimeout(()=>{
					resolve(data);
					console.log(data);
				},time * 1000);
			})
		}
	}
	
	const schedule = new Schedule();
	schedule.addHighTask(create(1));
	schedule.addLowTask(create(3));
	schedule.addLowTask(create(4));
	
	schedule.run();
	
	schedule.addLowTask(create(5));
	schedule.addHighTask(create(0));
	schedule.addHighTask(create(2));