与 Iterator 接口的关系
首先,我们要知道一下类数组之所以可以转为数组的原因,是因为有iterator遍历器。而Generator 函数既是状态机,又是一个遍历器对象生成函数。
模拟一个iterator的实现过程如下:
原理:任意一个对象的Symbol.iterator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。
function fn(){
let obj = {0:1,1:2,2:3,length:3,[Symbol.iterator]:function(){
let that = this;
let index = 0;
return {
next(){
return {value:that[index],done:index++===that.length}
}
}
}
}
let arr = [...obj];
console.log(arr,Array.isArray(arr));
}
fn();
再看一下通过generator实现的iterator接口:
原理:由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的Symbol.iterator属性,从而使得该对象具有 Iterator 接口。
function fns(){
// 给类数组 添加迭代方法 generator用法 koa1 基于generator dva
let obj = {0:1,1:2,2:3,length:3,[Symbol.iterator]:function*(){
let that = this;
let index = 0;
while(index !== that.length){
yield that[index++];
}
}};
let arr = [...obj];
console.log(Array.isArray(arr),arr);
}
fns();
generator作用
1.解决异步编程的问题
function * fns(){
let a = yield 1;
console.log(a); // ?
let b = yield 2;
console.log(b);
return b;
}
let it = fns();
let { value} = it.next(); // 第一次next传递参数是无意义的
it.next('100'); // 在传递参数 就会把结果传递给上一次yield的返回值
it.next('200');
let fs = require('mz/fs');
function * readAge(){
let content = yield fs.readFile('./name1.txt','utf8');
let age = yield fs.readFile(content,'utf8');
return age;
}
function co(it){ // express + koa 中间件原理
return new Promise((resolve,reject)=>{
// 如果是异步迭代
function next(r){ // 默认只要没有迭代完成 就不能的调用next
let {value,done} = it.next(r);
if(!done){ // 没有完成 他才是一个promise
value.then(r=>{
next(r);
},reject)
}else{
resolve(r);
};
}
next();
});
}
co(readAge()).then(data=>{
console.log(data);
}).catch(err=>{
console.log(err);
});
aysnc,await语法糖
// es7 async + await node 7.6 以上 generator + co语法糖
// let fs = require('mz/fs');
async function readAge(){ // 全部 async + await + promise
try{
let content = await fs.readFile('./name1.txt','utf8');
let age = await fs.readFile(content,'utf8');
return age;
}catch(e){
console.log('error',e);
}
}
// async 函数之行后 返回的是一个promise
readAge().then(data=>{
console.log(data);
}).catch(err=>{
console.log(err);
});