Generator 简介
生成器,本身是函数,执行后返回迭代对象,函数内部要配合 yield
使用 Generator
函数会分段执行,遇到 yield
即暂停。
特点
- function 和函数名之间需要带 *。
- 函数体内部 yield 表达式,产出不同的背部状态(值)。
演示
// function 和函数名之间需要带 *
function * test (){
yield 'a';
console.log('1');
yield 'b';
console.log('2');
yield 'c';
console.log('3');
return 'd';
}
let g = test(); // g 是迭代对象 所以有next 方法
og.next(); // 会返回对象{value: 'a', done: false}
og.next(); // 1 会返回对象{value: 'b', done: false}
og.next(); // 2 会返回对象{value: 'c', done: fasle}
og.next(); // 3 会返回对象{value: 'd', done: true}
上面的代码简单的讲了 Generator
的用法,在 函数声明的时候在函数名前添加 * (星号)。 函数体内部 yield 表达式,产出不同的背部状态(值)。g 是迭代对象,可以使用 next() 方法。
遇到 yield
会暂停,上面的打印顺序,在第二次执行 next() 的时候会打印出 1。但是余下的不打印出来。就说明遇到 yield
会暂停。
next 的参数
// function 和函数名之间需要带 *
function * test (){
let val1 = yield 'a';
console.log(val1);
let val2 = yield 'b';
console.log(val2);
let val3 = yield 'c';
console.log(val3);
return 'd';
}
let g = test(); // g 是迭代对象 所以有next 方法
console.log(g.next()) // 打印的是{value: 'a', done: false}
因为上面的代码中在 g.next()
之后,程序才执行到 **yield ‘a’ **就没有执行了,没有执行到 **let val1 = **就被暂停了。在执行到 **yield ‘b’ **的时候,才会执行 **let val1 = ,**赋值的是 next()的参数。
**
// function 和函数名之间需要带 *
function * test (){
let val1 = yield 'a';
console.log(val1);
let val2 = yield 'b';
console.log(val2);
let val3 = yield 'c';
console.log(val3);
return 'd';
}
let g = test(); // g 是迭代对象 所以有next 方法
console.log(g.next()) // 打印的是{value: 'a', done: false}
console.log(g.next('ccc')) // 打印的是ccc {value: 'b', done: false}
Generator 改写迭代函数
let obj = {
0: 'a',
1: 'b',
2: 'c'
length:3,
[Symbol.iterator]: function(){
let curIndex = 0;
let next = ()=>{
return {
value: this[curIndex],
done: this.length == ++curIndex;
}
}
return{
next
}
}
}
我在之前写了这个代码,让 obj 可以被迭代,我们可以也可以使 Generator
来写。
let obj = {
0: 'a',
1: 'b',
2: 'c'
length:3,
[Symbol.iterator]: function *(){
let currIndex = 0;
while (currIndex != this.length){
yield this[currIndex];
currIndex++;
}
}
}
conosle.log([...obj]);
使用 Generator 解决回调地狱
let fs = require('fs');
function readFile (path){
return new Promise((res,rej) =>{
fs.readFile(path,'utf-8',(err,data)=>{
if(data){
res(data);
} else {
rej(err);
}
})
})
}
readFile('xx/xx').then((val)=>{
return readFile(val)
}).then((val)=>{
return readFile(val)
})
// 使用Generator
function * read(){
let val1 = yield readFild('xx/xx');
let val2 = yield readFild(val1);
let val3 = yield readFild(val2);
return val3;
}
let g = read();
function Co(it){
return new Promise((res,rej) =>{
let next = ()=>{
let {value,done} = it.next();
if(done){
res(value)
} else {
value.then((val) =>{
next(val)
},rej)
}
}
next();
})
}
Co(read()).then((val) =>{
conosle.log(val)
})
