目錄
1. 生成器函數(shù)的定義和使用
2. 暫停和恢復執(zhí)行
3. 與其他語言特性的配合使用
Iterator Protocol 迭代器協(xié)議?
解構賦值?
生成器和 Promise 的組合使用?
????????使用 Promise:
????????使用 async/await:
委托給另外一個Generator函數(shù)
????????Generators 是 JavaScript 中的一種特殊函數(shù),它們可以暫停執(zhí)行并根據(jù)需要生成多個值。通過 yield 關鍵字,生成器函數(shù)可以在每次被調(diào)用時產(chǎn)生一個新值,這使得它們非常適合處理大量數(shù)據(jù)或需要延遲計算的場景。本文將詳細介紹 generators 的作用、用法以及與其他語言特性的配合使用。
1. 生成器函數(shù)的定義和使用
????????生成器函數(shù)是通過一個特殊的函數(shù)關鍵字 function*
來定義的。在生成器函數(shù)內(nèi)部,可以使用 yield
關鍵字來指定需要生成的值。以下是生成器函數(shù)的示例:
function* myGenerator() {
yield 'Apple';
yield 'Banana';
yield 'Cherry';
}
const generator = myGenerator();
console.log(generator.next()); // 輸出: { value: 'Apple', done: false }
console.log(generator.next()); // 輸出: { value: 'Banana ', done: false }
console.log(generator.next()); // 輸出: { value: 'Cherry', done: false }
console.log(generator.next()); // 輸出: { value: undefined, done: true }
????????通過調(diào)用生成器函數(shù),我們可以獲得一個生成器對象 generator
。每次調(diào)用 generator.next()
都會返回一個包含 value
和 done
屬性的對象。
-
value
?表示下一個生成的值。 -
done
?表示是否還有更多的值需要生成。當所有值都被生成后,done
?為?true
。
2. 暫停和恢復執(zhí)行
????????生成器函數(shù)的強大之處在于它們能夠暫停和恢復執(zhí)行,這意味著可以在需要時延遲計算或逐步處理大量數(shù)據(jù),而不是一次性全部處理。以下示例展示了如何利用生成器函數(shù)處理大型數(shù)據(jù)集:
function* generateNumbers() {
for (let i = 0; i <= 1000000; i++) {
yield i;
}
}
const numbersGenerator = generateNumbers();
for (let number of numbersGenerator) {
console.log(number);
}
????????在上述示例中,我們定義了一個生成器函數(shù) generateNumbers()
,它會生成一個從 0 到 1000000 的數(shù)字序列。通過 yield
關鍵字,每次循環(huán)都會產(chǎn)生一個新的數(shù)字,并在迭代過程中輸出到控制臺。通過這種方式,我們可以逐步處理巨大的數(shù)據(jù)集,避免一次性加載整個數(shù)據(jù)集導致的性能問題。
3. 與其他語言特性的配合使用
????????生成器函數(shù)在與其他 JavaScript 特性結合使用時,可以發(fā)揮更大的作用。
-
Iterator Protocol 迭代器協(xié)議?
????????由于生成器函數(shù)返回的是一個可迭代對象,因此可以通過?for...of
?循環(huán)來逐個訪問生成的值。
function* shoppingList() {
yield 'Milk';
yield 'Eggs';
yield 'Bread';
}
const myCart = shoppingList();
for (let item of myCart) {
console.log(item);
}
-
解構賦值?
????????可以通過在生成器函數(shù)中使用解構賦值來獲取生成的值的特定部分:
function* personDetails() {
yield ["John", "Doe"];
yield ["Jane", "Smith"];
}
const fullNameGenerator = personDetails();
for (let [firstName, lastName] of fullNameGenerator) {
console.log(firstName, lastName);
}
-
生成器和 Promise 的組合使用?
????????生成器函數(shù)與異步編程結合使用,可以實現(xiàn)更靈活的控制流,簡化異步操作的處理。下面我們分別介紹在生成器函數(shù)中如何使用 Promise 和 async/await 來處理異步編程。
????????使用 Promise:
function fetchTodos() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(['Todo 1', 'Todo 2', 'Todo 3']);
}, 2000);
});
}
function* todoGenerator() {
yield fetchTodos();
}
let generator = todoGenerator();
let promise = generator.next().value;
promise.then(todos => {
console.log(todos); // ['Todo 1', 'Todo 2', 'Todo 3']
});
????????在上述代碼中,我們定義了一個異步函數(shù) fetchTodos()
,它返回一個 Promise 對象,在 2 秒鐘后會 resolve 一個包含待辦事項的數(shù)組。然后,我們定義了一個生成器函數(shù) todoGenerator()
,其中通過 yield
關鍵字將 fetchTodos()
函數(shù)作為生成器的值進行暫停。
????????在生成器對象上調(diào)用 next()
方法后,我們可以獲取到 fetchTodos()
返回的 Promise 對象,然后可以使用 .then()
方法處理該 Promise 的結果。
????????使用 async/await:
function fetchTodo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Todo');
}, 2000);
});
}
function* todoGenerator() {
try {
let result = yield fetchTodo();
console.log(result); // 'Todo'
console.log('Generator continues...');
// 可以在生成器函數(shù)中根據(jù)需要使用多個異步操作
let anotherResult = yield someAsyncOperation();
console.log(anotherResult);
// ...
} catch (error) {
console.error(error);
}
}
async function main() {
const generator = todoGenerator();
try {
while (true) {
const { value, done } = generator.next();
if (done) {
break;
}
await value;
}
} catch (error) {
console.error(error);
}
}
main();
????????在上面的示例中:
-
fetchTodo()
函數(shù)返回一個 Promise 對象,表示獲取待辦事項。生成器函數(shù)todoGenerator()
使用yield
暫停執(zhí)行,并等待該 Promise 結果。 -
在
main()
函數(shù)中,我們創(chuàng)建了一個迭代器對象generator
,通過循環(huán)并使用await
關鍵字來依次執(zhí)行生成器函數(shù)中的異步操作。 -
生成器函數(shù)中可以根據(jù)需要使用多個異步操作,使用
yield
暫停執(zhí)行并等待每個操作完成。捕獲可能的錯誤,可以使用try-catch
塊。
? ? ? ? PS. 生成器函數(shù)本身并不返回 Promise 對象,因此我們需要將生成器函數(shù)與 main()
函數(shù)結合使用,以確保異步操作按照預期順序執(zhí)行。
????????總的來說,通過在生成器函數(shù)中結合 Promise、async/await 等異步編程特性,可以使生成器函數(shù)的控制流更加靈活、簡潔和可讀,從而提升異步編程的開發(fā)體驗。
-
委托給另外一個Generator函數(shù)
????????委托(delegating)給另一個 Generator 函數(shù)是 Generator 函數(shù)在使用上的一種常見用法,它允許一個生成器函數(shù)調(diào)用另一個生成器函數(shù),并將后者的生成器值逐個 yield 出來。這種委托機制可以簡化代碼結構,提高可讀性,同時靈活地處理多個生成器之間的協(xié)作關系。
????????示例代碼:
function* generator1() {
yield 1;
yield 2;
}
function* generator2() {
yield 'a';
yield 'b';
}
function* combinedGenerator() {
yield* generator1(); // 委托generator1()
yield* generator2(); // 委托generator2()
yield 'Final value';
}
let generator = combinedGenerator();
console.log(generator.next()); // { value: 1, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 'a', done: false }
console.log(generator.next()); // { value: 'b', done: false }
console.log(generator.next()); // { value: 'Final value', done: false }
console.log(generator.next()); // { value: undefined, done: true }
????????在上述代碼中,我們定義了三個生成器函數(shù):generator1()
、generator2()
和 combinedGenerator()
。其中,combinedGenerator()
是我們將要創(chuàng)建的委托生成器函數(shù)。
????????在 combinedGenerator()
中,通過使用 yield*
表達式,我們可以將執(zhí)行權委托給其他生成器函數(shù),即將 generator1()
和 generator2()
的生成器值依次逐個 yield 出來。這樣,在使用 combinedGenerator()
生成的生成器對象上調(diào)用 next()
方法時,它會檢查當前生成器函數(shù)是否有委托的生成器函數(shù)可供調(diào)用。
????????值得注意的是,通過委托給其他生成器函數(shù),不僅可以在合并生成器值時保持代碼的模塊化和可復用性,還可以處理更復雜的生成器協(xié)作場景。在實際開發(fā)中,你還可以根據(jù)具體需求嵌套多個委托關系,以實現(xiàn)更靈活和高效的生成器編程。
? ? ? ? 另外如果在委托生成器函數(shù)中發(fā)生異常(如:委托的生成器函數(shù)中出現(xiàn)錯誤、被主動生成器函數(shù)提前結束),該異常會被傳遞回主生成器函數(shù)并拋出。文章來源:http://www.zghlxwxcb.cn/news/detail-520892.html
????????通過委托機制,JavaScript 中的 Generator 函數(shù)能夠更好地組織和控制生成器之間的協(xié)作關系,使得代碼更具可讀性、可維護性,并且支持構建復雜的生成器流程。文章來源地址http://www.zghlxwxcb.cn/news/detail-520892.html
到了這里,關于JavaScript 生成器函數(shù)詳解:優(yōu)雅處理異步任務流的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!