Generator 生成器函数
生成器函数的声明和调用
生成器函数是 ES6 提供的一种 异步编程解决方案,语法行为与传统函数完全不同。
*的位置没有限制- 使用
function * gen()和yield可以声明一个生成器函数。生成器函数返回的结果是迭代器对象,调用迭代器对象的next方法可以得到yield语句后的值。 - 每一个
yield相当于函数的暂停标记,也可以认为是一个分隔符,每调用一次next(),生成器函数就往下执行一段。 next方法可以传递实参,作为yield语句的返回值
例如以下生成器函数中,3 个 yield 语句将函数内部分成了 4 段。
function* generator() {
console.log('before 111'); // 生成器第 1 段
yield 111;
console.log('before 222'); // 生成器第 1 段
yield 222;
console.log('before 333'); // 生成器第 1 段
yield 333;
console.log('after 333'); // 生成器第 1 段
}
let iter = generator();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
/*
before 111
{ value: 111, done: false }
before 222
{ value: 222, done: false }
before 333
{ value: 333, done: false }
after 333
{ value: undefined, done: true }
*/Copy to clipboardErrorCopied
12.2 生成器函数的参数传递
function* generator(arg) {
console.log(arg); // 生成器第 1 段
let one = yield 111;
console.log(one); // 生成器第 2 段
let two = yield 222;
console.log(two); // 生成器第 3 段
let three = yield 333;
console.log(three); // 生成器第 4 段
}
let iter = generator('aaa'); // 传给生成器第 1 段
console.log(iter.next());
console.log(iter.next('bbb')); // 传给生成器第 2 段,作为这一段开始的 yield 语句返回值
console.log(iter.next('ccc')); // 传给生成器第 3 段,作为这一段开始的 yield 语句返回值
console.log(iter.next('ddd')); // 传给生成器第 4 段,作为这一段开始的 yield 语句返回值
/*
aaa
{ value: 111, done: false }
bbb
{ value: 222, done: false }
ccc
{ value: 333, done: false }
ddd
{ value: undefined, done: true }
*/Copy to clipboardErrorCopied
12.3 生成器函数案例
案例1:1s后输出111,2s后输出222,3s后输出333
-
传统方式:嵌套太多,代码复杂,产生 回调地狱。
setTimeout(() => { console.log(111); setTimeout(() => { console.log(222); setTimeout(() => { console.log(333); }, 3000); }, 2000); }, 1000);Copy to clipboardErrorCopied -
生成器实现:结构简洁明了
function one() { setTimeout(() => { console.log(111); iter.next(); }, 1000); } function two() { setTimeout(() => { console.log(222); iter.next(); }, 2000); } function three() { setTimeout(() => { console.log(333); }, 3000); } function* generator() { yield one(); yield two(); yield three(); } let iter = generator(); iter.next();Copy to clipboardErrorCopied
案例2:生成器函数模拟每隔1s获取商品数据
function getUsers() {
setTimeout(() => {
let data = '用户数据';
iter.next(data); // 传参给生成器函数的第 2 段,后面类似
}, 1000);
}
function getOrders() {
setTimeout(() => {
let data = '订单数据';
iter.next(data);
}, 1000);
}
function getGoods() {
setTimeout(() => {
let data = '商品数据';
iter.next(data);
}, 1000);
}
function* generator() {
let users = yield getUsers();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}
let iter = generator();
iter.next();