JavaScript 中的 Generator 函数 是一种特殊的函数类型,它能够中断并恢复执行,这使得它在处理复杂的异步逻辑、协程等场景中非常有用。它的行为与普通的函数不同,因为它可以在执行过程中暂停,允许函数在某个点上“暂停”执行,之后可以继续从暂停点执行。
目录
什么是 Generator 函数?
Generator 函数通过 function*
声明,返回一个特殊的 Generator 对象,其核心机制是 yield
关键字。这个对象有一个可以“暂停”并在以后恢复执行的能力。
当调用一个 Generator 函数时,它不会立即执行,而是返回一个 Generator 对象。
调用next()函数在每个 yield
语句处暂停。当我们调用 next()
时,它会继续执行到下一个 yield
例子:
function* count() {
console.log("Start");
yield 1;
console.log("Continue");
yield 2;
console.log("End");
yield 3;
}
const counter = count();// 返回 Generator 对象
console.log(counter.next()); // Start 1
console.log(counter.next()); // Continue 2
console.log(counter.next()); // End 3
1.next()
方法
作用
next()
是控制 Generator 执行的主要方法,它会恢复 Generator 函数的执行,直到下一个yield
。- 每次调用
next()
,都会返回一个对象{ value, done }
:value
: 当前yield
表达式的返回值。done
: 布尔值,指示生成器是否已完成执行。
用法与返回值
function* gen() {
yield 1;
yield 2;
return 3;
}
const g = gen();
console.log(g.next()); // { value: 1, done: false }
console.log(g.next()); // { value: 2, done: false }
console.log(g.next()); // { value: 3, done: true }
console.log(g.next()); // { value: undefined, done: true }
g.next()
:调用next()
时,Generator 会继续执行,直到遇到下一个yield
或函数结束。如果没有yield
,它会直接返回一个done: true
对象。
参数传递
next()
可以接收一个参数,这个参数会作为上一次 yield
表达式的返回值,传递给生成器。
function* gen() {
const a = yield 'What is your name?';
const b = yield 'What is your age?';
return `${a} is ${b} years old.`;
}
const g = gen();
console.log(g.next()); // { value: 'What is your name?', done: false }
console.log(g.next('Alice')); // { value: 'What is your age?', done: false }
console.log(g.next(30)); // { value: 'Alice is 30 years old.', done: true }
在上述代码中,第一次 next()
返回一个字符串 'What is your name?'
。当我们向生成器传递参数('Alice'
和 30
)时,参数会依次传递给 a
和 b
,最终返回 "Alice is 30 years old."
。
3. throw()
方法
作用
throw()
方法可以用来在 Generator 函数中抛出错误。- 它会中断当前的
yield
并跳到最近的catch
块中。如果 Generator 中没有try-catch
语句捕获错误,那么throw()
会终止执行,并返回一个done: true
的结果。
用法与返回值
function* gen() {
try {
yield 1;
} catch (err) {
console.log(err); // 捕获到错误
yield 2;
}
yield 3;
}
const g = gen();
console.log(g.next()); // { value: 1, done: false }
console.log(g.throw("Oops!")); // "Oops!" { value: 2, done: false }
console.log(g.next()); // { value: 3, done: true }
g.throw("Oops!")
:在执行到yield 1
时,抛出一个错误Oops!
,这个错误会被try-catch
捕获,并在捕获后继续执行yield 2
。如果throw()
被调用的时机不合适(比如没有try-catch
),生成器将停止执行并返回一个{ value: undefined, done: true }
对象。
没有 catch
时的行为
function* gen() {
yield 1;
yield 2;
}
const g = gen();
console.log(g.next()); // { value: 1, done: false }
console.log(g.throw("Error")); // Error { value: undefined, done: true }
在这个例子中,调用 g.throw()
会导致生成器抛出错误并终止执行,因为没有 catch
语句来捕获该错误。
4. return()
方法
作用
return()
用于提前结束 Generator 函数,并返回一个结果。return()
会使得生成器结束执行,并返回{ value, done: true }
对象,done
属性为true
。- 返回的
value
会作为返回值传递给return()
调用的地方。
用法与返回值
function* gen() {
yield 1;
yield 2;
return 3;
}
const g = gen();
console.log(g.next()); // { value: 1, done: false }
console.log(g.return(4)); // { value: 4, done: true }
console.log(g.next()); // { value: undefined, done: true }
g.return(4)
:这个方法会立即结束生成器,并返回{ value: 4, done: true }
。注意:如果在 Generator 函数中调用return
,它会停止 Generator 的执行。
5. next()
, throw()
, return()
的总结与对比
方法 | 作用 | 返回值 | 适用场景 |
---|---|---|---|
next() | 恢复执行 Generator,直到下一个 yield 或结束 | { value: any, done: boolean } | 用于继续执行 Generator,并返回下一个 yield 的值。 |
throw() | 在 Generator 中抛出一个错误 | { value: any, done: boolean } | 用于处理错误,并在 Generator 内部抛出异常。 |
return() | 结束 Generator 函数的执行 | { value: any, done: true } | 用于提前结束 Generator,并返回结果。 |
总结
Generator 函数和其方法(next()
, throw()
, return()
)提供了对函数执行流程的精确控制。通过 yield
暂停执行,next()
恢复执行,throw()
处理错误,return()
提前结束生成器,这使得 Generator 函数在处理异步编程、协程、流控制等场景中非常有用。掌握这些方法,可以帮助开发者更好地控制异步操作和复杂逻辑的执行过程。