📅  最后修改于: 2023-12-03 15:01:48.172000             🧑  作者: Mango
在 JavaScript 中,生成器是一个特殊的函数,它能够暂停执行,保存状态,并在需要时继续执行。我们可以使用生成器来结束回调地狱,使代码更加简洁和易于理解。
生成器函数需要使用 function*
关键字来声明,且函数体中必须包含关键字 yield
。示例如下:
function* generator() {
yield 'hello';
yield 'world';
yield '!';
}
const gen = generator();
console.log(gen.next()); // {value: 'hello', done: false}
console.log(gen.next()); // {value: 'world', done: false}
console.log(gen.next()); // {value: '!', done: false}
console.log(gen.next()); // {value: undefined, done: true}
在上述示例中,我们定义了一个生成器函数 generator
,并通过调用该函数创建了一个生成器对象 gen
。通过调用生成器对象的 next
方法,我们可以逐一获取每一次 yield
表达式的值。
yield
表达式可以看作是生成器函数的暂停标志,它将表示函数执行状态的对象返回给调用者,并暂停函数的执行。每次调用生成器对象的 next
方法时,函数将从上一次暂停的位置恢复执行,并修改表示函数执行状态的对象的 value
属性。
function* add(a, b) {
yield a + b; // 3
const c = yield; // yield 的 return value 为 undefined
yield a + b + c;
}
const gen = add(1, 2);
console.log(gen.next()); // {value: 3, done: false}
console.log(gen.next()); // {value: undefined, done: false}
console.log(gen.next(4)); // {value: 7, done: false}
console.log(gen.next()); // {value: undefined, done: true}
在上述示例中,我们定义了一个生成器函数 add
,并通过调用该函数创建了一个生成器对象 gen
。在第一次调用 gen.next()
时,yield a + b;
的值为 3
,表示执行到了该语句。在第二次调用 gen.next()
时,函数执行到了 const c = yield
,并等待外部传入一个参数。在第三次调用 gen.next(4)
时,yield a + b + c
的值为 7
,表示执行到了该语句。
从第二次调用 gen.next()
开始,我们没有传入参数,此时 yield
表达式的返回值将为 undefined
。
生成器可以实现异步的效果,代码更加清晰易读。下面的示例展示了如何使用生成器实现异步逻辑:
function asyncFunc() {
return new Promise(resolve => {
setTimeout(() => {
resolve('hello world');
}, 2000);
});
}
function* asyncGenerator() {
const result = yield asyncFunc();
console.log(result);
}
const gen = asyncGenerator();
const promise = gen.next().value;
promise.then(res => gen.next(res));
在上述示例中,我们通过定义一个异步函数 asyncFunc
,在生成器函数的语句中使用 yield asyncFunc()
,并将其返回值赋值给变量 result
。我们通过返回 Promise 对象的方式来实现异步,最后在调用 promise.then
时,将异步执行结果传回给生成器对象。当异步函数执行完成后,console.log(result)
将在控制台中打印出 'hello world'。
在使用生成器函数时需要注意以下几点:
next
方法不需要传入参数,但如果传入参数,则表示上一次 yield
表达式的返回值。yield
表达式暂停函数执行,任何其它语句都会导致语法错误。通过本文,我们了解了 JavaScript 中的生成器函数及其基本语法、应用场景和注意事项。使用生成器函数可以优雅地解决异步回调地狱和可读性问题,但需要遵循其使用规范。