最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解ES9的新特性之異步遍歷Async iteration

 更新時間:2021年06月03日 11:02:18   作者:flydean  
在ES6中,引入了同步iteration的概念,隨著ES8中的Async操作符的引用,是不是可以在一異步操作中進(jìn)行遍歷操作呢?今天要給大家講一講ES9中的異步遍歷的新特性Async iteration。

異步遍歷

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

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

Iterable

先看下Iterable的定義:

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

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

Iterator

interface Iterator {
    next() : IteratorResult;
}

可以從Iterable中構(gòu)建Iterator。Iterator是一個類似游標(biāo)的概念,可以通過next訪問到IteratorResult。

IteratorResult

IteratorResult是每次調(diào)用next方法得到的數(shù)據(jù)。

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

IteratorResult中除了有一個value值表示要獲取到的數(shù)據(jù)之外,還有一個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ù)據(jù),如果我們獲取的是異步數(shù)據(jù),比如從http端下載下來的文件,我們想要一行一行的對文件進(jìn)行遍歷。因為讀取一行數(shù)據(jù)是異步操作,那么這就涉及到了異步數(shù)據(jù)的遍歷。

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

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

也許你會想,我們是不是可以把異步讀取一行的操作封裝在Promise中,然后用同步的方式去遍歷呢?

想法很好,不過這種情況下,異步操作是否執(zhí)行完畢是無法檢測到的。所以方法并不可行。

于是ES9引入了異步遍歷的概念:

1.可以通過Symbol.asyncIterator來獲取到異步iterables中的iterator。

2.異步iterator的next()方法返回Promises對象,其中包含IteratorResults。

所以,我們看下異步遍歷的API定義:

interface AsyncIterable {
    [Symbol.asyncIterator]() : AsyncIterator;
}
interface AsyncIterator {
    next() : Promise<IteratorResult>;
}
interface IteratorResult {
    value: any;
    done: boolean;
}

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

這里我們主要關(guān)注一下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轉(zhuǎn)換成為異步的iterators。然后返回的值被轉(zhuǎn)換成為了Promise。

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

也就是說會把: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é)果是一樣的。

異步iterable的生成

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

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

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

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

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

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

因為返回的是Promise對象,所以我們不需要等待異步執(zhí)行的結(jié)果完成,就可以再次調(diào)用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ù)據(jù),于是我們可以這樣用:

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

在generator一文中,我們講到了在generator中調(diào)用generator。也就是在一個生產(chǎn)器中通過使用yield*來調(diào)用另外一個生成器。

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

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。

通過調(diào)用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 }

以上就是詳解ES9的新特性之異步遍歷Async iteration的詳細(xì)內(nèi)容,更多關(guān)于ES9的新特性之異步遍歷Async iteration的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • js實現(xiàn)圖片旋轉(zhuǎn)的三種方法

    js實現(xiàn)圖片旋轉(zhuǎn)的三種方法

    這篇文章主要介紹了js實現(xiàn)圖片旋轉(zhuǎn)的三種方法,需要的朋友可以參考下
    2014-04-04
  • Javascript 對象(object)合并操作實例分析

    Javascript 對象(object)合并操作實例分析

    這篇文章主要介紹了Javascript 對象(object)合并操作,結(jié)合實例形式分析了javascript基于jQuery的extend方法、對象屬性、遍歷賦值等操作實現(xiàn)對象合并相關(guān)操作技巧與使用注意事項,需要的朋友可以參考下
    2019-07-07
  • bootstrap基礎(chǔ)知識學(xué)習(xí)筆記

    bootstrap基礎(chǔ)知識學(xué)習(xí)筆記

    這篇文章主要針對bootstrap基礎(chǔ)知識為大家整理了詳細(xì)的學(xué)習(xí)筆記,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • JavaScript之filter_動力節(jié)點(diǎn)Java學(xué)院整理

    JavaScript之filter_動力節(jié)點(diǎn)Java學(xué)院整理

    filter也是一個常用的操作,它用于把Array的某些元素過濾掉,然后返回剩下的元素。下面通過實例代碼給大家簡答介紹下javascript中的filter,需要的的朋友參考下吧
    2017-06-06
  • BootStrap便簽頁的簡單應(yīng)用

    BootStrap便簽頁的簡單應(yīng)用

    本文通過實例代碼給大家簡單介紹了bootstrap便簽頁的簡單應(yīng)用,非常不錯,具有參考借鑒價值,需要的朋友參考下
    2017-01-01
  • js按指定格式顯示日期時間的樣式代碼

    js按指定格式顯示日期時間的樣式代碼

    按指定格式顯示日期時間在開發(fā)與時間相關(guān)的應(yīng)用時非常有用,接下來與大家分享下格式化顯示日期時間的方法,感興趣的朋友可以參考下哈
    2013-04-04
  • js創(chuàng)建數(shù)組的簡單方法

    js創(chuàng)建數(shù)組的簡單方法

    下面小編就為大家?guī)硪黄狫S創(chuàng)建數(shù)組的簡單方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-07-07
  • 一文教會你微信小程序如何實現(xiàn)登錄

    一文教會你微信小程序如何實現(xiàn)登錄

    微信小程序頁面畫好后,需要開始做一系列和用戶的交互功能了,首先就是登錄,這篇文章主要給大家介紹了關(guān)于微信小程序如何實現(xiàn)登錄的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • js如何引入wasm文件

    js如何引入wasm文件

    這篇文章主要介紹了js如何引入wasm文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • js通過window.open(url)下載文件并修改文件名

    js通過window.open(url)下載文件并修改文件名

    這篇文章主要給大家介紹了關(guān)于js如何通過window.open(url)下載文件并修改文件名的相關(guān)資料,我們知道下載文件是一個非常常見的需求,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08

最新評論

柏乡县| 宁强县| 广安市| 汝阳县| 定远县| 丽江市| 上蔡县| 永胜县| 杂多县| 万盛区| 鄂托克旗| 隆子县| 安阳县| 潞城市| 金湖县| 库车县| 大冶市| 璧山县| 东乡族自治县| 曲松县| 宜兰市| 城口县| 巴东县| 屏山县| 宁陵县| 桐梓县| 武汉市| 屏南县| 武穴市| 乐清市| 隆尧县| 乐至县| 安陆市| 措美县| 永春县| 万安县| 会宁县| 宁武县| 集安市| 镇赉县| 同仁县|