生成器的背景
Promise的缺陷:还是有大量的回调函数,普通函数多一个*,直到调用next方法才执行,这使得异步调用逐渐扁平化。
生成器是一种返回迭代器的函数,通过function关键字之后的表示。函数中会用到新的关键字yield。星号可以紧挨着function 也可以中间加一个空格。
生成器函数是 ES6 提供的一种更好的异步编程解决方案,旨在减少回调,语法行为与传统函数完全不同。
基本用法
生成器返回的是一个迭代器对象。可以用函数声明和函数表达式创建生成器。但是不能用箭头函数
function * a(){};
const b = function *(){};
console.log(a()) // Object [Generator] {};
yield后边返回的是next返回值的value
function * a() {
yield 1;
yield 2;
yield 3;
}
const i = a();
console.log(i.next());
console.log(i.next());
console.log(i.next());
console.log(i.next());
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: undefined, done: true }
生成器解决回调地狱
假设现在有这样一个场景,我们根据小明的身份证号获取小明的基础信息,根据小明的基础信息的地址查询小明的家乡景区,根据景区获取景区的详细介绍。最后用基础信息和家乡介绍生成小明的自我介绍。
ES5的写法
function getIntroduce(cardId) {
setTimeout(() => {
const personInfo = {
id: cardId,
name: '小明',
address: '北京',
age:19
}
console.log(personInfo);
setTimeout(() => {
const Attractions = ['故宫', '长城', '颐和园'];
console.log(Attractions);
setTimeout(() => {
const sebnceIntro = Attractions[0] + '是一个五A级景区,他的历史悠久,记载着很多。。。';
console.log(sebnceIntro);
const res = `我叫${ personInfo.name },今年${ personInfo.age }来自${ personInfo.address },我的家乡有谱很多名胜古迹,比如${ Attractions.join(',') }等等,其中${sebnceIntro}希望大家有机会常来玩`;
console.log(res);
}, 1000);
}, 3000);
}, 200);
};
getIntroduce(1)
生成器的写法:解决回调地狱
function getPersonInfo(id){
setTimeout(() => {
const res = {
id: id,
name: '小明',
address: '北京',
age:19
}
// 异步拿到之前的数据之后 才让代码继续执行
introduce.next(res);
},200);
}
function getSenceListByName(id) {
setTimeout(() => {
const res = ['故宫','长城','颐和园'];
introduce.next(res);
},3000);
}
function getSenceInfoByName(name) {
setTimeout(() => {
const res = name + '是一个五A级景区,他的历史悠久,记载着很多。。。';
introduce.next(res);
},1000);
}
function * getIntroduce(cardId) {
const personInfo = yield getPersonInfo(cardId);
console.log(personInfo);
const Attractions = yield getSenceListByName(personInfo.address);
console.log(Attractions);
const sebnceIntro = yield getSenceInfoByName(Attractions[0]);
console.log(sebnceIntro);
const res = `我叫${personInfo.name},今年${personInfo.age}来自${personInfo.address},我的家乡有谱很多名胜古迹,比如${ Attractions.join(',') }等等,其中${sebnceIntro}希望大家有机会常来玩`;
console.log(res);
}
const introduce = getIntroduce(1);
introduce.next();
console.log();
高级生成器
给迭代器传参数,如果给next函数传参数,这个参数就会作为上一个yield语句的返回值。这个也是迭代器实现异步编程的关键特点。
function* a() {
const res1 = yield 1;
const res2 = yield 2;
const res3 = yield 3;
console.log(res1,res2,res3) // AAA BBB CCC
};
const i = a();
console.log(i.next());
console.log(i.next('AAA'));
console.log(i.next('BBB'));
console.log(i.next('CCC'));
抛出错误
允许通过throw给迭代器抛出错误。
返回语句
允许生成器用return语句结束函数,且设置最后一个next的value。
委托生成器
给yield加一个星号,可以将两个生成器合成一个生成器。
function* b() {
yield 'mm';
yield 'bb';
};
function* a() {
yield * b();
yield 2;
yield 3;
};
const i = a();
for (m of i) {
console.log(m);
}
// mm bb 2 3