简单介绍
生成器就是以一个特殊的函数,用于实现异步编程。
定义特殊:在定义的时候在function 和函数名之间加上一个 * 号。
执行特殊:执行的时候直接调用不会执行该函数里面的内容,而是输出是一个迭代器对象,可以调用next方法,用这个方法才可以调用函数。
function * gen(){
console.log('这是一个生成器');
}
let iterator = gen()
//直接调用函数
console.log(iterator);
输出
Object [Generator] {}
加上next方法
console.log(iterator.next());
输出
这是一个生成器
{ value: undefined, done: true }
生成器函数可以出现yield语句(算作函数代码的分隔符)
//yield 定义的是调用next方法返回的value值,next遇到yield就会停止
function * gen(){
console.log('111');
yield '两只老虎'
console.log('222');
yield '跑得快'
console.log('222');
}
let iterator = gen()
console.log(iterator.next());
结果
111
{ value: '两只老虎', done: false }
111 是函数执行结果
{ value: '两只老虎', done: false } 是next方法返回的对象。
上面iterator都出现了,所以我们很自然的想到可以用for...of啦,来试试
function * gen(){
console.log('111');
yield '两只老虎';
console.log('222');
yield '跑得快';
console.log('333');
}
for(let v of gen()){
console.log(v);
console.log("------");
}
结果
111
两只老虎
------
222
跑得快
------
333
可以发现,每次拿到的数据是把yield那条语句执行完
生成器函数的参数传递
1、生成器可以传入参数
function * gen(arg){
console.log(arg);
yield '两只老虎';
yield '跑得快';
}
let iterator = gen('参数');
iterator.next()
结果
参数
2、next方法在调用时可以传入参数
传入的实参是上一个yield语句返回的结果
function * gen(){
let one = yield '两只老虎';
console.log(one);
yield '跑得快';
}
let iterator = gen();
iterator.next()
iterator.next('next参数')
结果
next参数
生成器函数解决异步编程问题
有哪些异步操作呢?比如说:文件操作,网络操作(Ajax, request),数据库操作。这里直接用延时函数来代替
实现目标:1s后获取用户数据,执行完成后2s后获取订单数据,执行完成后3s后获取商品数据。
需要注意的是,1、需要在每个定时器内部加上iterator.next()方法,或者选择在执行的时候每次手动调用next方法;2、数据获取完之后用next传参给yield,可以来处理数据。
function getUsers(){
setTimeout(() => {
let data = '用户数据';
iterator.next(data);
}, 1000);
}
function getOrders(){
setTimeout(() => {
let data = '订单数据';
iterator.next(data);
}, 2000);
}
function getGoods(){
setTimeout(() => {
let data = '商品数据';
iterator.next(data);
}, 3000);
}
function * gen(){
let users = yield getUsers();
console.log(users);
let oders = yield getOrders();
console.log(oders);
let goods = yield getGoods();
console.log(goods);
}
let iterator = gen();
iterator.next()
优点:可以解决回调地狱问题。