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));