日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
掌握 JavaScript 中的迭代器和生成器

迭代器和生成器是 ES6 中引入的特性。迭代器通過一次消費一個項目列表來提高效率,類似于數(shù)據(jù)流。生成器是一種能夠暫停執(zhí)行的特殊函數(shù)。調(diào)用生成器允許以塊的形式(一次一個)生成數(shù)據(jù),而無需先將其存儲在列表中。下面就來深入理解 JavaScript 中的迭代器和生成器,看看它們是如何使用的,又有何妙用!

創(chuàng)新互聯(lián)建站主要從事成都網(wǎng)站建設、網(wǎng)站制作、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務涿鹿,十年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:18980820575

迭代器

JavaScript 中的迭代器可以分別兩種:同步迭代器和異步迭代器。

1. 同步迭代器

(1)迭代器和可迭代對象

在 JavaScript 中有很多方法可以遍歷數(shù)據(jù)結構。例如,使用 for? 循環(huán)或使用 while 循環(huán)。迭代器具有類似的功能,但有顯著差異。

迭代器只需要知道集合中的當前位置,而其他循環(huán)則需要預先加載整個集合才能循環(huán)遍歷它。迭代器使用 next() 方法訪問集合中的下一個元素。但是,為了使用迭代器,值或數(shù)據(jù)結構應該是可迭代的。數(shù)組、字符串、映射、集合是 JavaScript 中的可迭代對象。普通對象是不可迭代的。

(2)定義迭代器

下面來看看集合不可迭代的場景:

const favouriteMovies = {
a: '哈利波特',
b: '指環(huán)王',
c: '尖峰時刻',
d: '星際穿越',
e: '速度與激情',
}

這個對象是不可迭代的。如果使用普通的 for 循環(huán)遍歷它,就會拋出錯誤。隨著 ES6 中迭代器的引入,可以將其轉換為可迭代對象以便遍歷它。這些稱為自定義迭代器。下面看看如何實現(xiàn)對象的遍歷并打印出來:

favouriteMovies[Symbol.iterator] = function() {
const ordered = Object.values(this).sort((a, b) => a - b);
let i = 0;
return {
next: () => ({
done: i >= ordered.length,
value: ordered[i++]
})
}
}

for (const v of favouriteMovies) {
console.log(v);
}

輸出結果如下:

哈利波特
指環(huán)王
尖峰時刻
星際穿越
速度與激情

這里使用 Symbol.iterator()? 來定義迭代器。任何具有 Symbol.iterator 鍵的結構都是可迭代的。

可迭代對象具有以下行為:

  1. 當 for..of 循環(huán)開始時,它首先查找錯誤。如果未找到,則它會訪問方法和定義該方法的對象。
  2. 以 for..of 循環(huán)方式迭代該對象。
  3. 使用該輸出對象的 next() 方法來獲取要返回的下一個值。
  4. 返回的值的格式為 done:boolean?, value: any?。返回 done:true 時循環(huán)結束。

下面來創(chuàng)建一個 LeapYear 對象,該對象返回范圍為 (start, end) 的閏年列表,并在后續(xù)閏年之間設置間隔。

class LeapYear {
constructor(start = 2020, end = 2040, interval = 4) {
this.start = start;
this.end = end;
this.interval = interval;
}
[Symbol.iterator]() {
let nextLeapYear = this.start;
return {
next: () => {
if (nextLeapYear <= this.end) {
let result = { value: nextLeapYear, done: false };
nextLeapYear += this.interval;
return result;
}
return { value: undefined, done: true };
},
};
}
}

在上面的代碼中,為自定義類型 LeapYear 實現(xiàn)了 Symbol.iterator() 方法。分別在 this.start? 和 this.end? 字段中有迭代的起點和終點。使用 this.interval來跟蹤迭代的第一個元素和下一個元素之間的間隔。

現(xiàn)在,可以在自定義類型上調(diào)用 for...of 循環(huán),并查看其行為和輸出值,就像默認數(shù)組類型一樣:

let leapYears = new LeapYear();
for (const leapYear of leapYears) {
console.log(leapYear);
}

輸出結果如下:

2020
2024
2028
2032
2036
2040

這里的 LeapYear? 通過 Symbol.iterator() 變成了可迭代對象。

在一些情況下,迭代器會比普通迭代更好。例如,在沒有隨機訪問的有序集合(如數(shù)組)中,迭代器的性能會更好,因為它可以直接根據(jù)當前位置檢索元素。但是,對于無序集合,由于沒有順序,就不會體驗到性能上的重大差異。

使用普通循環(huán)算法,例如 for? 循環(huán)或 while 循環(huán),您只能循環(huán)遍歷允許迭代的集合:

const favourtieMovies = [
'哈利波特',
'指環(huán)王',
'尖峰時刻',
'星際穿越',
'速度與激情',
];

for (let i=0; i < favourtieMovies.length; i++) {
console.log(favouriteMovies[i]);
}

let i = 0;
while (i < favourtieMovies.length) {
console.log(favourtieMovies[i]);
i++;
}

由于數(shù)組是可迭代的,因此可以使用 for 循環(huán)遍歷。我們也可以為上面實現(xiàn)一個迭代器,這將允許更好地訪問基于當前位置的元素,而無需加載整個集合。代碼如下:

const iterator = favourtieMovies[Symbol.iterator]();

iterator.next(); // { value: '哈利波特', done: false }
iterator.next(); // { value: '指環(huán)王', done: false }
iterator.next(); // { value: '尖峰時刻', done: false }
iterator.next(); // { value: '星際穿越', done: false }
iterator.next(); // { value: '速度與激情', done: false }
iterator.next(); // { value: undefined, done: true }

next() 方法將返回迭代器的結果。它包括兩個值;集合中的元素和完成狀態(tài)??梢钥吹?,當遍歷完成后,即使訪問數(shù)組外的元素,也不會拋出錯誤。它只會返回一個具有 undefined? 值和完成狀態(tài)為 true 的對象。

(3)使用場景

那為什么向自定義對象中添加迭代器呢?我們也可以編寫自定義函數(shù)來遍歷對象以完成同樣的事情。

實際上,迭代器是一種標準化自定義對象的優(yōu)雅實現(xiàn)方式,它為自定義數(shù)據(jù)結構提供了一種在更大的 JS 環(huán)境中很好地工作的方法。因此,提供自定義數(shù)據(jù)結構的庫經(jīng)常會使用迭代器。例如,  Immutable.JS 庫就使用迭代器為其自定義對象(如Map)。所以,如果需要為封裝良好的自定義數(shù)據(jù)結構提供原生迭代功能,就考慮使用迭代器。

2. 異步迭代器

JavaScript 中的異步迭代對象是實現(xiàn) Symbol.asyncIterator 的對象:

const asyncIterable = {
[Symbol.asyncIterator]: function() {

}
};

我們可以將一個函數(shù)分配給 [Symbol.asyncIterator]? 以返回一個迭代器對象。迭代器對象應符合帶有 next() 方法的迭代器協(xié)議(類似于同步迭代器)。

下面來添加迭代器:

const asyncIterable = {
[Symbol.asyncIterator]: function() {
let count = 0;

return {
next() {
count++;
if (count <= 3) {
return Promise.resolve({ value: count, done: false });
}

return Promise.resolve({ value: count, done: true });
}
};
}
};

這里用 Promise.resolve? 包裝了返回的對象。下面來執(zhí)行 next() 方法:

const go = asyncIterable[Symbol.asyncIterator]();

go.next().then(iterator => console.log(iterator.value));
go.next().then(iterator => console.log(iterator.value));

輸出結果如下:

1
2

也可以使用 for await...of 來對異步迭代對象進行迭代:

async function consumer() {
for await (const asyncIterableElement of asyncIterable) {
console.log(asyncIterableElement);
}
}

consumer();

異步迭代器和迭代器是異步生成器的基礎,后面會介紹異步生成器。

生成器

JavaScript 中的生成器可以分別兩種:同步生成器和異步生成器。

1. 同步生成器

(1)基本概念

生成器是一個可以暫停和恢復并可以產(chǎn)生多個值的過程。JavaScript 中的生成器由一個生成器函數(shù)組成,它返回一個可迭代 Generator 對象。

生成器是對 JavaScript 的強大補充。它們可以維護狀態(tài),提供一種制作迭代器的有效方法,并且能夠處理無限數(shù)據(jù)流,可用于在前端實現(xiàn)無限滾動等。此外,當與 Promises 一起使用時,生成器可以模擬 async/await 功能,這使我們能夠以更直接和可讀的方式處理異步代碼。盡管 async/await 是處理常見、簡單的異步用例(例如從 API 獲取數(shù)據(jù))的一種更普遍的方式,但生成器具有更高級的功能。

生成器函數(shù)是返回生成器對象的函數(shù),由 function 關鍵字后面跟星號 (*) 定義,如下所示:

function* generatorFunction() {}

有時,我們可能會在函數(shù)名稱旁邊看到星號,而不是 function? 關鍵字,例如 function *generatorFunction()?,它的工作原理是相同的,但 function* 是一種更廣泛接受的語法。

生成器函數(shù)也可以在表達式中定義,就像常規(guī)函數(shù)一樣:

const generatorFunction = function* () {}

生成器甚至可以是對象或類的方法:

// 生成器作為對象的方法
const generatorObj = {
*generatorMethod() {},
}

// 生成器作為類的方法
class GeneratorClass {
*generatorMethod() {}
}

下面的例子都將使用生成器函數(shù)聲明得語法。

注意:與常規(guī)函數(shù)不同,生成器不能使用 new 關鍵字構造,也不能與箭頭函數(shù)結合使用。

現(xiàn)在我們知道了如何聲明生成器函數(shù),下面來看看生成器返回的可迭代生成器對象。

(2)生成器對象

傳統(tǒng)的 JavaScript 函數(shù)會在遇到return? 關鍵字時返回一個值。如果省略 return? 關鍵字,函數(shù)將隱式返回 undefined。

例如,在下面的代碼中,我們聲明了一個 sum() 函數(shù),它返回一個值,該值是兩個整數(shù)參數(shù)的和:

function sum(a, b) {
return a + b
}

調(diào)用該函數(shù)會返回一個值,該值是參數(shù)的總和:

const value = sum(5, 6) // 11

而生成器函數(shù)不會立即返回值,而是返回一個可迭代的生成器對象。在下面的例子中,我們聲明了一個函數(shù)并給它一個單一的返回值,就像一個標準的函數(shù):

function* generatorFunction() {
return 'Hello, Generator!'
}

當調(diào)用生成器函數(shù)時,它將返回生成器對象,我們可以將其分配給一個變量:

const generator = generatorFunction()

如果這是一個常規(guī)函數(shù),我們希望生成器為我們提供函數(shù)中返回的字符串。然而,我們實際得到的是一個處于掛起狀態(tài)的對象。因此,調(diào)用生成器將提供類似于以下內(nèi)容的輸出:

generatorFunction {}
[[GeneratorLocation]]: VM335:1
[[Prototype]]: Generator
[[GeneratorState]]: "suspended"
[[GeneratorFunction]]: ?* generatorFunction()
[[GeneratorReceiver]]: Window

函數(shù)返回的生成器對象是一個迭代器。迭代器是一個具有可用的 next()? 方法的對象,該方法用于迭代一系列值。next() 方法返回一個對象,其包含兩個屬性:

  • value:當前步驟的值;
  • done:布爾值,指示生成器中是否有更多值。

next() 方法必須遵循以下規(guī)則:

  • 返回一個帶有 done: false 的對象來繼續(xù)迭代;
  • 返回一個帶有 done: true 的對象來停止迭代。

下面就來在生成器上調(diào)用 next() 并獲取迭代器的當前值和狀態(tài):

generator.next()

這將得到以下輸出結果:

{value: "Hello, Generator!", done: true}

調(diào)用 next()? 時的返回值為 Hello, Generator!?,并且 done? 的狀態(tài)為 true,因為該值來自關閉迭代器的返回值。由于迭代器完成,生成器函數(shù)的狀態(tài)將從掛起變?yōu)殛P閉。這時再次調(diào)用生成器將輸出以下內(nèi)容:

generatorFunction {}

除此之外,生成器函數(shù)也有區(qū)別于普通函數(shù)的獨特特征。下面我們就來了解一下 yield 運算符并看看生成器如何暫停和恢復執(zhí)行。

(3)yield 運算符

生成器為 JavaScript 引入了一個新的關鍵字:yield。**yield**?** 可以暫停生成器函數(shù)并返回 **yield** 之后的值,從而提供一種輕量級的方法來遍歷值。**

在下面的例子中,我們將使用不同的值暫停生成器函數(shù)三次,并在最后返回一個值。然后將生成器對象分配給 generator 變量。

function* generatorFunction() {
yield 'One'
yield 'Two'
yield 'Three'

return 'Hello, Generator!'
}

const generator = generatorFunction()

現(xiàn)在,當我們在生成器函數(shù)上調(diào)用 next()? 時,它會在每次遇到 yield 時暫停。done? 會在每次 yield? 后設置為 false?,表示生成器還沒有結束。一旦遇到 return?,或者函數(shù)中沒有更多的 yield? 時,done? 就會變?yōu)?nbsp;true,生成器函數(shù)就結束了。

連續(xù)四次調(diào)用 next() 方法:

generator.next()
generator.next()
generator.next()
generator.next()

這些將按順序得到以下結果:

{value: "One", done: false}
{value: "Two", done: false}
{value: "Three", done: false}
{value: "Hello, Generator!", done: true}

next() 非常適合從迭代器對象中提取有限數(shù)據(jù)。

注意,生成器不需要 return?;如果省略,最后一次迭代將返回 {value: undefined, done: true},生成器完成后對 next() 的任何后續(xù)調(diào)用也是如此。

(4)遍歷生成器

使用 next()? 方法可以遍歷生成器對象,接收完整對象的所有 value? 和 done? 屬性。不過,就像 Array、Map 和 Set 一樣,Generator 遵循迭代協(xié)議,并且可以使用 for...of 進行迭代:

function* generatorFunction() {
yield 'One'
yield 'Two'
yield 'Three'

return 'Hello, Generator!'
}

const generator = generatorFunction()

for (const value of generator) {
console.log(value)
}

輸出結果如下:

One
Two
Three

擴展運算符也可用于將生成器的值分配給數(shù)組:

const values = [...generator]

console.log(values)

輸出結果如下:

['One', 'Two', 'Three']

可以看到,擴展運算符和 for...of? 都不會將 return? 的值計入 value。

注意:雖然這兩種方法對于有限生成器都是有效的,但如果生成器正在處理無限數(shù)據(jù)流,則無法在不創(chuàng)建無限循環(huán)的情況下直接使用擴展運算符或 for...of。

我們還可以從迭代結果中解構值:

const [a, b, c]= generator;
console.log(a);
console.log(b);
console.log(c);

輸出結果如下:

One
Two
Three

(5)關閉生成器

如我們所見,生成器可以通過遍歷其所有值將其 done? 屬性設置為 true? 并將其狀態(tài)設置為 closed? 。除此之外,還有兩種方法可以立即關閉生成器:使用 return()? 方法和使用 throw() 方法。

使用 return()?,生成器可以在任何時候終止,就像在函數(shù)體中的 return? 語句一樣??梢詫?shù)傳遞給 return(),或將其留空以表示未定義的值。

下面來創(chuàng)建一個具有 yield? 值但在函數(shù)定義中沒有 return 的生成器:

function* generatorFunction() {
yield 'One'
yield 'Two'
yield 'Three'
}

const generator = generatorFunction()

第一個 next()? 將返回“One?”,并將 done? 設置為 false?。如果在那之后立即在生成器對象上調(diào)用 return()? 方法,將獲得傳遞的值并將 done? 設置為 true?。對 next() 的任何額外調(diào)用都會給出默認的已完成生成器響應,其中包含一個 undefined 值。

generator.next()
generator.return('Return!')
generator.next()

輸出結果如下:

{value: "Neo", done: false}
{value: "Return!", done: true}
{value: undefined, done: true}

return()? 方法會強制生成器對象完成并忽略任何其他 yield 關鍵字。當需要使函數(shù)可取消時,這在異步編程中特別有用,例如當用戶想要執(zhí)行不同的操作時中斷數(shù)據(jù)請求,因為無法直接取消 Promise。

如果生成器函數(shù)的主體有捕獲和處理錯誤的方法,則可以使用 throw() 方法將錯誤拋出到生成器中。這將啟動生成器,拋出錯誤并終止生成器。

下面來在生成器函數(shù)體內(nèi)放一個 try...catch 并在發(fā)現(xiàn)錯誤時記錄錯誤:

function* generatorFunction() {
try {
yield 'One'
yield 'Two'
} catch (error) {
console.log(error)
}
}

const generator = generatorFunction()

現(xiàn)在來運行 next()? 方法,然后運行 throw() 方法:

generator.next()
generator.throw(new Error('Error!'))

輸出結果如下:

{value: "One", done: false}
Error: Error!
{value: undefined, done: true}

使用 throw()? 可以將錯誤注入到生成器中,該錯誤被 try...catch 捕獲并記錄到控制臺。

(6)生成器對象方法和狀態(tài)

下面是生成器對象的方法:

  • next():返回生成器中的后面的值;
  • return():在生成器中返回一個值并結束生成器;
  • throw():拋出錯誤并結束生成器。

下面是生成器對象的狀態(tài):

  • suspended:生成器已停止執(zhí)行但尚未終止。
  • closed:生成器因遇到錯誤、返回或遍歷所有值而終止。

(7)yield 委托

除了常規(guī)的 yield? 運算符之外,生成器還可以使用 yield*? 表達式將更多值委托給另一個生成器。當在生成器中遇到 yield*? 時,它將進入委托生成器并開始遍歷所有 yield? 直到該生成器關閉。這可以用于分離不同的生成器函數(shù)以在語義上組織代碼,同時仍然讓它們的所有 **yield** 都可以按正確的順序迭代。

下面來創(chuàng)建兩個生成器函數(shù),其中一個將對另一個進行 yield* 操作:

function* delegate() {
yield 3
yield 4
}

function* begin() {
yield 1
yield 2
yield* delegate()
}

接下來,遍歷 begin() 生成器函數(shù):

const generator = begin()

for (const value of generator) {
console.log(value)
}

輸出結果如下:

1
2
3
4

外部的生成器(begin)生成值 1 和 2,然后使用 yield* 委托給另一個生成器(delegate),返回 3 和 4。

yield*? 還可以委托給任何可迭代的對象,例如 Array 或 Map。yield? 委托有助于組織代碼,因為生成器中任何想要使用 yield 的函數(shù)也必須是一個生成器。

(8)在生成器中傳遞值

上面的例子中,我們使用生成器作為迭代器,并且在每次迭代中產(chǎn)生值。除了產(chǎn)生值之外,生成器還可以使用 next()? 中的值。在這種情況下,yield 將包含一個值。

需要注意,調(diào)用的第一個 next()? 不會傳遞值,而只會啟動生成器。為了證明這一點,可以記錄 yield? 的值并使用一些值調(diào)用 next() 幾次。

function* generatorFunction() {
console.log(yield)
console.log(yield)

return 'End'
}

const generator = generatorFunction()

generator.next()
generator.next(100)
generator.next(200)

輸出結果如下:

100
200
{value: "End", done: true}

除此之外,也可以為生成器提供初始值。下面來創(chuàng)建一個 for? 循環(huán)并將每個值傳遞給 next()? 方法,同時將一個參數(shù)傳遞給 inital 函數(shù):

function* generatorFunction(value) {
while (true) {
value = yield value * 10
}
}

const generator = generatorFunction(0)

for (let i = 0; i < 5; i++) {
console.log(generator.next(i).value)
}

這將從 next() 中檢索值并為下一次迭代生成一個新值,該值是前一個值乘以 10。輸出結果如下:

0
10
20
30
40

處理啟動生成器的另一種方法是將生成器包裝在一個函數(shù)中,該函數(shù)將會在執(zhí)行任何其他操作之前調(diào)用 next() 一次。

(9)async/await

async/await 使處理異步數(shù)據(jù)更簡單、更容易理解。生成器具有比異步函數(shù)更廣泛的功能,但能夠復制類似的行為。以這種方式實現(xiàn)異步編程可以增加代碼的靈活性。

下面來構建一個異步函數(shù),它使用 Fetch API 獲取數(shù)據(jù)并將響應記錄到控制臺。

首先定義一個名為 getUsers? 的異步函數(shù),該函數(shù)從 API 獲取數(shù)據(jù)并返回一個對象數(shù)組,然后調(diào)用 getUsers:

const getUsers = async function () {
const response = await fetch('https://jsonplaceholder.typicode.com/users')
const json = await response.json()

return json
}

getUsers().then((response) => console.log(response))

輸出結果如下:

使用生成器可以創(chuàng)建幾乎相同但不使用 async/await 關鍵字的效果。相反,它將使用我們創(chuàng)建的新函數(shù),并產(chǎn)生值而不是等待 Promise。

const getUsers = asyncAlt(function* () {
const response = yield fetch('https://jsonplaceholder.typicode.com/users')
const json = yield response.json()

return json
})

getUsers().then((response) => console.log(response))

如我們所見,它看起來與 async/await 實現(xiàn)幾乎相同,除了有一個生成器函數(shù)被傳入以產(chǎn)生值。

現(xiàn)在可以創(chuàng)建一個類似于異步函數(shù)的 asyncAlt? 函數(shù)。asyncAlt? 有一個 generatorFunction? 參數(shù),它是產(chǎn)生 fetch 返回的 Promise 的函數(shù)。asyncAlt 返回函數(shù)本身,并 resolve 它得到的每個 Promise,直到最后一個:

function asyncAlt(generatorFunction) {
return function () {
// 創(chuàng)建并分配生成器對象
const generator = generatorFunction()

// 定義一個接受生成器下一次迭代的函數(shù)
function resolve(next) {
// 如果生成器關閉并且沒有更多的值可以生成,則解析最后一個值
if (next.done) {
return Promise.resolve(next.value)
}

// 如果仍有值可以產(chǎn)生,那么它們就是Promise,必須 resolved。
return Promise.resolve(next.value).then((response) => {
return resolve(generator.next(response))
})
}

// 開始 resolve Promise
return resolve(generator.next())
}
}

這樣就會得到和async/await一樣的結果:

盡管這個方法可以為代碼增加靈活性,但通常 async/await 是更好的選擇,因為它抽象了實現(xiàn)細節(jié)并讓開發(fā)者專注于編寫高效代碼。

(10)使用場景

很多開發(fā)人員認為生成器函數(shù)視為一種奇特的 JavaScript 功能,在現(xiàn)實中幾乎沒有應用。在大多數(shù)情況下,確實用不到生成器。

生成器的優(yōu)點:

  • 惰性求值:除非需要,否則不計算值。它提供按需計算。只有需要它時,value 才會存在。
  • 內(nèi)存效率高:由于惰性求值,生成器的內(nèi)存效率非常高,因為它不會為預先生成的未使用值分配不必要的內(nèi)存位置。
  • 更簡潔的代碼:生成器提供更簡潔的代碼,尤其是在異步行為中。

生成器在對性能要求高的場景中有很大的用處。特別是,它們適用于以下場景:

  • 處理大文件和數(shù)據(jù)集。
  • 生成無限的數(shù)據(jù)序列。
  • 按需計算昂貴的邏輯。

Redux sagas 就是實踐中使用的生成器的一個很好的例子。它是一個用于管理redux應用異步操作的中間件,redux-saga 通過創(chuàng)建 sagas 將所有異步操作邏輯收集在一個地方集中處理,可以用來代替 redux-thunk 中間件。

2. 異步生成器

ECMAScript 2018 中引入了異步生成器的概念,它是一種特殊類型的異步函數(shù),可以隨意停止和恢復其執(zhí)行。

同步生成器函數(shù)和異步生成器函數(shù)的區(qū)別在于,后者從迭代器對象返回一個異步的、基于 Promise 的結果。

要想創(chuàng)建異步生成器函數(shù),需要聲明一個帶有星號 * 的生成器函數(shù),前綴為 async:

async function* asyncGenerator() {

}

一旦進入函數(shù),就可以使用 yield 來暫停執(zhí)行:

async function* asyncGenerator() {
yield 'One'
yield 'Two'
}

這里 yield 會暫停執(zhí)行并返回一個迭代器對象給調(diào)用者。這個對象既是可迭代對象,又是迭代器。

異步生成器函數(shù)不會像常規(guī)函數(shù)那樣在一步中計算出所有結果。相反,它會逐步提取值。我們可以使用兩種方法從異步生成器解析 Promise:

  • 在迭代器對象上調(diào)用 next();
  • 使用 for await...of 異步迭代。

對于上面的例子,可以這樣做:

async function* asyncGenerator() {
yield 'One';
yield 'Two';
}

const go = asyncGenerator();

go.next().then(iterator => console.log(iterator.value));
go.next().then(iterator => console.log(iterator.value));

輸出結果如下:

'One';
'Two'

另一種方法使用異步迭代 for await...of。要使用異步迭代,需要用 async 函數(shù)包裝它:

async function* asyncGenerator() {
yield 'One';
yield 'Two';
}

async function consumer() {
for await (const value of asyncGenerator()) {
console.log(value);
}
}

consumer();

for await...of 非常適合提取非有限數(shù)據(jù)流。


當前題目:掌握 JavaScript 中的迭代器和生成器
URL網(wǎng)址:http://www.dlmjj.cn/article/cdesdoc.html