前言
在ES6 中萝风,JS擁有了內(nèi)部對同步迭代數(shù)據(jù)的支持, 這篇文章主要的是介紹異步迭代Asynchronous iteration
可免,
異步迭代
實現(xiàn)
- 通過內(nèi)部方法
Symbol.asyncIterator
調(diào)用 - 在每一個迭代調(diào)用
next()
方法蔼水,通過返回一個promise實現(xiàn)
for-await-of
async function f(){
for await(const x of createAsyncIterable(['a','b'])){
console.log(x);
}
}
返回值
每次調(diào)用next()
方法牺荠, 返回值是類似·Promise.resolve({ value: 123, done: false })
的結(jié)構(gòu)
Promise.all()
和Asynchronous iteration
對比
for (const x of await Promise.all(syncIterableOverPromises));
for await (const x of syncIterableOverPromises);
第二種寫法會更快婚被, 因為第一種寫法必須等Promise.all()
執(zhí)行完成子姜,才會去執(zhí)行for語句塊的內(nèi)容, 但是 for-wait-of燎竖,只要promise里面的第一項執(zhí)行完成璃弄,就會去執(zhí)行for語句塊的內(nèi)容
異步生成器
示例
async function* createAsyncIterable(syncIterable) {
for (const elem of syncIterable) {
yield elem;
}
}
注意:
- 號放在function關(guān)鍵字后面
- 和一般的generater不同的是,這個返回值是一個Promise构回,這個Promise最終的結(jié)果為
{value,done}
在異步生成器async generator
中使用await
在異步生成器中可以使用 await 和 for-await-of, 例如
async function* prefixLines(asyncIterable) {
for await (const line of asyncIterable) {
yield '> ' + line;
}
}
在異步生成器中使用 yield*
基本上和一般的generater一樣谢揪,不過yield后面的計算對象如果是同步的東東,會自動會轉(zhuǎn)成異步的捐凭,就像使用了for-await-of 一樣
async function* gen1() {
yield 'a';
yield 'b';
return 2;
}
async function* gen2() {
const result = yield* gen1(); // (A)
// result === 2
}
異步生成器的相關(guān)規(guī)定
異步生成器總共涉及以下的幾個概念:
- 兩個新接口:
AsyncIterable
和AsyncIterator
- 一個Symbol:
Symbol.asyncIterator
- 新的對象: %AsyncGenerator%, %AsyncFromSyncIteratorPrototype%, %AsyncGeneratorFunction%, %AsyncGeneratorPrototype%, %AsyncIteratorPrototype
異步生成器的內(nèi)部原理
兩個異步生成器函數(shù)內(nèi)部的屬性
-
[[AsyncGeneratorState]]
,這個的值為"suspendedStart", "suspendedYield", "executing", "completed"凳鬓,"undefined"(在初始化之前) -
[[AsyncGeneratorQueue]]
保存著等待調(diào)用的next/throw/return
, 每一個隊列項包含兩個字段-
[[Completion]]
next()
,throw()
或者return()
的參數(shù)茁肠,completion的類型(normal, throw, return)是方法進(jìn)入隊列的時候指定的,決定當(dāng)它出隊列的時候調(diào)用哪一個缩举?#不太理解# -
[[Capability]]
pending狀態(tài)的Promise的容量垦梆?#不太理解#
-
管理隊列主要是通過下列兩個操作
-
AsyncGeneratorEnqueue()
, 通過這個操作入隊列,這個操作是被next(), return() 和 throw() 觸發(fā)的仅孩,在這之后托猩,如果這個generator的狀態(tài)不是executing
的話,AsyncGeneratorResumeNext()
會被調(diào)用:- 因此辽慕, 如果一個generator內(nèi)部調(diào)用next(), return() 或者 throw()京腥,這個操作會是異步的
- await 會導(dǎo)致generator暫停, 但是它的狀態(tài)會保持在
executing
溅蛉, 所以不會因為調(diào)用 AsyncGeneratorEnqueue()而使這個generator重新開始
AsyncGeneratorResumeNext()
公浪, 通過這個操作出隊,出隊是在入隊之后船侧,Promise的狀態(tài)終止(AsyncGeneratorResolve()
或者AsyncGeneratorReject()
)后執(zhí)行欠气,如果隊列里面是空的,就立即返回镜撩,否則预柒,則執(zhí)行隊列中第一個元素