generator(生成器)是ES6标准引入的新的数据类型,与函数类似,但它可以返回多次。
generator由 function * 定义,并且除了使用return,还可以通过定义 yield 返回多次。
generator不像普通函数一样,调用就会执行,需要通过next()方法执行:
function* helloGenerator() {
console.log('this is generator');
}
var h = helloGenerator(); // 这里调用不会执行console
h.next(); // 执行console
例子:
要编写一个斐波那契数列的函数:
function fib(max) {
var t, a = 0, b = 1, arr = [0, 1];
while (arr.length < max) {
[a, b] = [b, a + b];
arr.push(b);
}
return arr;
}
console.log(fib(5)); // [0, 1, 1, 2, 3]
函数只能返回一次,使用generator,可以实现返回多次结果。
function* fib(max) {
var t, a = 0, b = 1, arr = [0, 1];
while (arr.length < max) {
[a, b] = [b, a + b];
arr.push(b);
yield arr;
}
if (max === 2) {
return arr
}
}
fib() 仅仅创建了一个generator对象,还没有去执行它。
执行generator有两种方式:
1、next() 方法:
var fun = fib(5);
console.log(fun.next()); // {value: Array(3), done: false}
console.log(fun.next()); // {value: Array(4), done: false}
console.log(fun.next()); // {value: Array(5), done: false}
console.log(fun.next()); // {value: undefined, done: true}
next() 方法会执行generator代码,每次遇到 yield,就会返回一个对象 {value: x, done: true / false}。value 就是 yield 的返回值,done为true时,表示这个generator已经全部执行完毕。
2、for ... of循环迭代generator对象
for (var arr of fib(5)) {
console.log(arr)
}
// (3) [0, 1, 1]
// (4) [0, 1, 1, 2]
// (5) [0, 1, 1, 2, 3]
这种方式没有返回值done,会自动判断可执行的yield。
解决回调地狱,异步代码按同步执行:
function prepare(success) {
setTimeout(function() {
console.log('prepare');
success(); // 执行成功后再执行下一个next()方法
},500)
}
function fired(success) {
setTimeout(function() {
console.log('fired');
success(); // 执行成功后再执行下一个next()方法
},500)
}
function stewed(success) {
setTimeout(function() {
console.log('stewed');
success(); // 执行成功后再执行下一个next()方法
},500)
}
function sdd(success) {
setTimeout(function() {
console.log('sdd');
success(); // 执行成功后再执行下一个next()方法
},500)
}
function serve(success) {
setTimeout(function() {
console.log('serve');
success(); // 执行成功后再执行下一个next()方法,此时返回结果done为true
},500)
}
function* task() {
yield prepare;
yield fired;
yield stewed;
yield sdd;
yield serve;
}
function run(fn) {
const gen = fn();
function next() {
const result = gen.next();
if (result.done) return;
result.value(next);
}
next();
}
run(task);
// 执行结果:
// prepare
// fired
// stewed
// sdd
// serve
网友评论