日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ES9的新特性:异步遍历Async iteration

發(fā)布時間:2024/2/28 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ES9的新特性:异步遍历Async iteration 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 簡介
  • 異步遍歷
  • 異步iterable的遍歷
  • 異步iterable的生成
  • 異步方法和異步生成器

簡介

在ES6中,引入了同步iteration的概念,隨著ES8中的Async操作符的引用,是不是可以在一異步操作中進行遍歷操作呢?

今天要給大家講一講ES9中的異步遍歷的新特性Async iteration。

異步遍歷

在講解異步遍歷之前,我們先回想一下ES6中的同步遍歷。

根據ES6的定義,iteration主要由三部分組成:

  • Iterable
  • 先看下Iterable的定義:

    interface Iterable {[Symbol.iterator]() : Iterator; }

    Iterable表示這個對象里面有可遍歷的數(shù)據,并且需要實現(xiàn)一個可以生成Iterator的工廠方法。

  • Iterator
  • interface Iterator {next() : IteratorResult; }

    可以從Iterable中構建Iterator。Iterator是一個類似游標的概念,可以通過next訪問到IteratorResult。

  • IteratorResult
  • IteratorResult是每次調用next方法得到的數(shù)據。

    interface IteratorResult {value: any;done: boolean; }

    IteratorResult中除了有一個value值表示要獲取到的數(shù)據之外,還有一個done,表示是否遍歷完成。

    下面是一個遍歷數(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ù)據,如果我們獲取的是異步數(shù)據,比如從http端下載下來的文件,我們想要一行一行的對文件進行遍歷。因為讀取一行數(shù)據是異步操作,那么這就涉及到了異步數(shù)據的遍歷。

    加入異步讀取文件的方法是readLinesFromFile,那么同步的遍歷方法,對異步來說就不再適用了:

    //不再適用 for (const line of readLinesFromFile(fileName)) {console.log(line); }

    也許你會想,我們是不是可以把異步讀取一行的操作封裝在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; }

    我們看一個異步遍歷的應用:

    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將會把一個同步的iterable轉換成一個異步的iterable,我們將會在下面一小節(jié)中看一下到底怎么生成的。

    這里我們主要關注一下asyncIterator的遍歷操作。

    因為ES8中引入了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 } }

    異步iterable的遍歷

    使用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來捕獲這個異常:

    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 則會將同步的iterators轉換成為異步的iterators。然后返回的值被轉換成為了Promise。

    如果同步的next本身返回的value就是Promise對象,則異步的返回值還是同樣的promise。

    也就是說會把:Iterable<Promise<T>> 轉換成為 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轉換成異步的Promise。

    async function main() {for await (const x of ['a', 'b']) {console.log(x);} } main();// Output: // c // d

    上面的例子將同步的常量轉換成為Promise。 可以看到兩者的結果是一樣的。

    異步iterable的生成

    回到上面的例子,我們使用createAsyncIterable(syncIterable)將syncIterable轉換成了AsyncIterable。

    我們看下這個方法是怎么實現(xiàn)的:

    async function* createAsyncIterable(syncIterable) {for (const elem of syncIterable) {yield elem;} }

    上面的代碼中,我們在一個普通的generator function前面加上async,表示的是異步的generator。

    對于普通的generator來說,每次調用next方法的時候,都會返回一個object {value,done} ,這個object對象是對yield值的封裝。

    對于一個異步的generator來說,每次調用next方法的時候,都會返回一個包含object {value,done} 的promise對象。這個object對象是對yield值的封裝。

    因為返回的是Promise對象,所以我們不需要等待異步執(zhí)行的結果完成,就可以再次調用next方法。

    我們可以通過一個Promise.all來同時執(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ù)據,于是我們可以這樣用:

    async function* prefixLines(asyncIterable) {for await (const line of asyncIterable) {yield '> ' + line;} }

    在generator一文中,我們講到了在generator中調用generator。也就是在一個生產器中通過使用yield*來調用另外一個生成器。

    同樣的,如果是在異步生成器中,我們可以做同樣的事情:

    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

    如果在異步生成器中拋出異常,這個異常也會被封裝在Promise中:

    async function* asyncGenerator() {throw new Error('Problem!'); } asyncGenerator().next() .catch(err => console.log(err)); // Error: Problem!

    異步方法和異步生成器

    異步方法是使用async function 聲明的方法,它會返回一個Promise對象。

    function中的return或throw異常會作為返回的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 * 申明的方法。它會返回一個異步的iterable。

    通過調用iterable的next方法,將會返回一個Promise。異步生成器中yield 的值會用來填充Promise的值。如果在生成器中拋出了異常,同樣會被Promise捕獲到。

    async function* gen() {yield 'hello'; } const genObj = gen(); genObj.next().then(x => console.log(x));// { value: 'hello', done: false }

    本文作者:flydean程序那些事

    本文鏈接:http://www.flydean.com/es9-async-iteration/

    本文來源:flydean的博客

    歡迎關注我的公眾號:「程序那些事」最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發(fā)現(xiàn)!

    超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

    總結

    以上是生活随笔為你收集整理的ES9的新特性:异步遍历Async iteration的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。