生成器函數(Generator Function)是 JavaScript 中一種特殊的函數,它可以在執行過程中暫停并在之后恢復執行。生成器函數使用 function*
語法定義,并且內部使用 yield
表達式來暫停函數執行并返回一個值。每次調用生成器函數返回的迭代器的 next
方法時,生成器函數會從上次暫停的地方繼續執行,直到遇到下一個 yield
表達式或函數結束。
生成器函數的定義和用法
定義生成器函數
生成器函數使用 function*
關鍵字定義:
function* generatorFunction() {yield 'First output';yield 'Second output';return 'Finished';
}
調用生成器函數
調用生成器函數會返回一個迭代器對象,該對象具有 next
方法:
const gen = generatorFunction();
迭代生成器函數
使用 next
方法迭代生成器函數,每次調用 next
方法,生成器函數會執行到下一個 yield
表達式,并返回一個對象 { value: any, done: boolean }
:
console.log(gen.next()); // { value: 'First output', done: false }
console.log(gen.next()); // { value: 'Second output', done: false }
console.log(gen.next()); // { value: 'Finished', done: true }
console.log(gen.next()); // { value: undefined, done: true }
生成器函數的特性
-
暫停和恢復執行:
生成器函數在遇到yield
表達式時會暫停執行,并返回yield
后的值。函數的狀態會被保存下來,下一次調用next
方法時會從暫停的地方繼續執行。 -
雙向通信:
可以通過next
方法傳遞參數給生成器函數,生成器函數內部可以接收這個參數并進行處理。 -
實現迭代器協議:
生成器函數返回的迭代器對象遵循迭代器協議,可以用于for...of
循環和其他需要迭代器的地方。
示例
簡單生成器函數
function* simpleGenerator() {yield 1;yield 2;yield 3;
}const gen = simpleGenerator();console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
雙向通信的生成器函數
function* counter() {let count = 0;while (true) {const increment = yield count;if (increment != null) {count += increment;} else {count++;}}
}const countGenerator = counter();console.log(countGenerator.next().value); // 0
console.log(countGenerator.next(2).value); // 2
console.log(countGenerator.next(3).value); // 5
console.log(countGenerator.next().value); // 6
用于異步操作的生成器函數
生成器函數可以與 Promise
結合使用,處理異步操作,使異步代碼更接近同步風格。
function fetchData(url) {return new Promise((resolve) => {setTimeout(() => {resolve(`Data from ${url}`);}, 1000);});
}function* asyncTaskQueue() {const data1 = yield fetchData('https://api.example.com/endpoint1');console.log(data1);const data2 = yield fetchData('https://api.example.com/endpoint2');console.log(data2);const data3 = yield fetchData('https://api.example.com/endpoint3');console.log(data3);
}function run(generator) {const iterator = generator();function handle(result) {if (result.done) return;result.value.then(data => {handle(iterator.next(data));});}handle(iterator.next());
}run(asyncTaskQueue);
生成器函數的優勢
- 靈活性:生成器函數可以暫停和恢復,適用于復雜的控制流邏輯。
- 雙向通信:可以通過
yield
和next
實現雙向數據傳遞。 - 內存友好:在處理大型數據集時,可以逐個生成數據項,而不是一次性加載所有數據。
- 異步編程:與
Promise
結合,可以更容易地處理異步操作。
生成器函數為 JavaScript 提供了一種強大而靈活的方式來處理迭代、異步操作和復雜的控制流。理解并善用生成器函數可以大大提升代碼的可讀性和可維護性。