這篇文章將為大家詳細(xì)講解有關(guān)ES9中新特性Async iteration的示例分析,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
創(chuàng)新互聯(lián)始終堅(jiān)持【策劃先行,效果至上】的經(jīng)營理念,通過多達(dá)十多年累計(jì)超上千家客戶的網(wǎng)站建設(shè)總結(jié)了一套系統(tǒng)有效的全網(wǎng)營銷解決方案,現(xiàn)已廣泛運(yùn)用于各行各業(yè)的客戶,其中包括:崗?fù)?/a>等企業(yè),備受客戶贊譽(yù)。
在ES6中,引入了同步iteration的概念,隨著ES8中的Async操作符的引用,是不是可以在一異步操作中進(jìn)行遍歷操作呢?
今天要給大家講一講ES9中的異步遍歷的新特性Async iteration。
在講解異步遍歷之前,我們先回想一下ES6中的同步遍歷。
根據(jù)ES6的定義,iteration主要由三部分組成:
1、Iterable
先看下Iterable的定義:
interface Iterable { [Symbol.iterator]() : Iterator; }
Iterable表示這個(gè)對象里面有可遍歷的數(shù)據(jù),并且需要實(shí)現(xiàn)一個(gè)可以生成Iterator的工廠方法。
2、Iterator
interface Iterator { next() : IteratorResult; }
可以從Iterable中構(gòu)建Iterator。Iterator是一個(gè)類似游標(biāo)的概念,可以通過next訪問到IteratorResult。
3、IteratorResult
IteratorResult是每次調(diào)用next方法得到的數(shù)據(jù)。
interface IteratorResult { value: any; done: boolean; }
IteratorResult中除了有一個(gè)value值表示要獲取到的數(shù)據(jù)之外,還有一個(gè)done,表示是否遍歷完成。
下面是一個(gè)遍歷數(shù)組的例子:
> const iterable = ['a', 'b']; > const iterator = iterable[Symbol.iterator](); > iterator.next() { value: 'a', done: false } > iterator.next() { value: 'b', done: false } > iterator.next() { value: undefined, done: true }
但是上的例子遍歷的是同步數(shù)據(jù),如果我們獲取的是異步數(shù)據(jù),比如從http端下載下來的文件,我們想要一行一行的對文件進(jìn)行遍歷。因?yàn)樽x取一行數(shù)據(jù)是異步操作,那么這就涉及到了異步數(shù)據(jù)的遍歷。
加入異步讀取文件的方法是readLinesFromFile,那么同步的遍歷方法,對異步來說就不再適用了:
//不再適用 for (const line of readLinesFromFile(fileName)) { console.log(line); }
也許你會(huì)想,我們是不是可以把異步讀取一行的操作封裝在Promise中,然后用同步的方式去遍歷呢?
想法很好,不過這種情況下,異步操作是否執(zhí)行完畢是無法檢測到的。所以方法并不可行。
于是ES9引入了異步遍歷的概念:
可以通過Symbol.asyncIterator來獲取到異步iterables中的iterator。
異步iterator的next()方法返回Promises對象,其中包含IteratorResults。
所以,我們看下異步遍歷的API定義:
interface AsyncIterable { [Symbol.asyncIterator]() : AsyncIterator; } interface AsyncIterator { next() : Promise<IteratorResult>; } interface IteratorResult { value: any; done: boolean; }
我們看一個(gè)異步遍歷的應(yīng)用:
const asyncIterable = createAsyncIterable(['a', 'b']); const asyncIterator = asyncIterable[Symbol.asyncIterator](); asyncIterator.next() .then(iterResult1 => { console.log(iterResult1); // { value: 'a', done: false } return asyncIterator.next(); }) .then(iterResult2 => { console.log(iterResult2); // { value: 'b', done: false } return asyncIterator.next(); }) .then(iterResult3 => { console.log(iterResult3); // { value: undefined, done: true } });
其中createAsyncIterable將會(huì)把一個(gè)同步的iterable轉(zhuǎn)換成一個(gè)異步的iterable,我們將會(huì)在下面一小節(jié)中看一下到底怎么生成的。
這里我們主要關(guān)注一下asyncIterator的遍歷操作。
因?yàn)镋S8中引入了Async操作符,我們也可以把上面的代碼,使用Async函數(shù)重寫:
async function f() { const asyncIterable = createAsyncIterable(['a', 'b']); const asyncIterator = asyncIterable[Symbol.asyncIterator](); console.log(await asyncIterator.next()); // { value: 'a', done: false } console.log(await asyncIterator.next()); // { value: 'b', done: false } console.log(await asyncIterator.next()); // { value: undefined, done: true } }
使用for-of可以遍歷同步iterable,使用 for-await-of 可以遍歷異步iterable。
async function f() { for await (const x of createAsyncIterable(['a', 'b'])) { console.log(x); } } // Output: // a // b
注意,await需要放在async函數(shù)中才行。
如果我們的異步遍歷中出現(xiàn)異常,則可以在 for-await-of 中使用try catch來捕獲這個(gè)異常:
function createRejectingIterable() { return { [Symbol.asyncIterator]() { return this; }, next() { return Promise.reject(new Error('Problem!')); }, }; } (async function () { try { for await (const x of createRejectingIterable()) { console.log(x); } } catch (e) { console.error(e); // Error: Problem! } })();
同步的iterable返回的是同步的iterators,next方法返回的是{value, done}。
如果使用 for-await-of 則會(huì)將同步的iterators轉(zhuǎn)換成為異步的iterators。然后返回的值被轉(zhuǎn)換成為了Promise。
如果同步的next本身返回的value就是Promise對象,則異步的返回值還是同樣的promise。
也就是說會(huì)把:Iterable<Promise<T>>
轉(zhuǎn)換成為 AsyncIterable<T>
,如下面的例子所示:
async function main() { const syncIterable = [ Promise.resolve('a'), Promise.resolve('b'), ]; for await (const x of syncIterable) { console.log(x); } } main(); // Output: // a // b
上面的例子將同步的Promise轉(zhuǎn)換成異步的Promise。
async function main() { for await (const x of ['a', 'b']) { console.log(x); } } main(); // Output: // c // d
上面的例子將同步的常量轉(zhuǎn)換成為Promise。 可以看到兩者的結(jié)果是一樣的。
回到上面的例子,我們使用createAsyncIterable(syncIterable)將syncIterable轉(zhuǎn)換成了AsyncIterable。
我們看下這個(gè)方法是怎么實(shí)現(xiàn)的:
async function* createAsyncIterable(syncIterable) { for (const elem of syncIterable) { yield elem; } }
上面的代碼中,我們在一個(gè)普通的generator function前面加上async,表示的是異步的generator。
對于普通的generator來說,每次調(diào)用next方法的時(shí)候,都會(huì)返回一個(gè)object {value,done} ,這個(gè)object對象是對yield值的封裝。
對于一個(gè)異步的generator來說,每次調(diào)用next方法的時(shí)候,都會(huì)返回一個(gè)包含object {value,done} 的promise對象。這個(gè)object對象是對yield值的封裝。
因?yàn)榉祷氐氖荘romise對象,所以我們不需要等待異步執(zhí)行的結(jié)果完成,就可以再次調(diào)用next方法。
我們可以通過一個(gè)Promise.all來同時(shí)執(zhí)行所有的異步Promise操作:
const asyncGenObj = createAsyncIterable(['a', 'b']); const [{value:v1},{value:v2}] = await Promise.all([ asyncGenObj.next(), asyncGenObj.next() ]); console.log(v1, v2); // a b
在createAsyncIterable中,我們是從同步的Iterable中創(chuàng)建異步的Iterable。
接下來我們看下如何從異步的Iterable中創(chuàng)建異步的Iterable。
從上一節(jié)我們知道,可以使用for-await-of 來讀取異步Iterable的數(shù)據(jù),于是我們可以這樣用:
async function* prefixLines(asyncIterable) { for await (const line of asyncIterable) { yield '> ' + line; } }
在generator一文中,我們講到了在generator中調(diào)用generator。也就是在一個(gè)生產(chǎn)器中通過使用yield*來調(diào)用另外一個(gè)生成器。
同樣的,如果是在異步生成器中,我們可以做同樣的事情:
async function* gen1() { yield 'a'; yield 'b'; return 2; } async function* gen2() { const result = yield* gen1(); // result === 2 } (async function () { for await (const x of gen2()) { console.log(x); } })(); // Output: // a // b
如果在異步生成器中拋出異常,這個(gè)異常也會(huì)被封裝在Promise中:
async function* asyncGenerator() { throw new Error('Problem!'); } asyncGenerator().next() .catch(err => console.log(err)); // Error: Problem!
異步方法是使用async function 聲明的方法,它會(huì)返回一個(gè)Promise對象。
function中的return或throw異常會(huì)作為返回的Promise中的value。
(async function () { return 'hello'; })() .then(x => console.log(x)); // hello (async function () { throw new Error('Problem!'); })() .catch(x => console.error(x)); // Error: Problem!
異步生成器是使用 async function * 申明的方法。它會(huì)返回一個(gè)異步的iterable。
通過調(diào)用iterable的next方法,將會(huì)返回一個(gè)Promise。異步生成器中yield 的值會(huì)用來填充Promise的值。如果在生成器中拋出了異常,同樣會(huì)被Promise捕獲到。
async function* gen() { yield 'hello'; } const genObj = gen(); genObj.next().then(x => console.log(x)); // { value: 'hello', done: false }
關(guān)于“ES9中新特性Async iteration的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯(cuò),請把它分享出去讓更多的人看到。
本文名稱:ES9中新特性Asynciteration的示例分析
鏈接地址:http://jinyejixie.com/article42/ipijhc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、面包屑導(dǎo)航、移動(dòng)網(wǎng)站建設(shè)、靜態(tài)網(wǎng)站、網(wǎng)站設(shè)計(jì)、電子商務(wù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)