Как лучше всего создать итератор asyn c? Должен ли я использовать функцию генератора asyn c или, скорее, использовать Symbol.asyncIterator? - PullRequest
1 голос
/ 14 июля 2020

Этот код работает так, как ожидалось:

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function getAsyncData() {
    await sleep(1000);  // simulate database/network delay...
    return [1, 2, 3, 4, 5];  // ...then return some data
}

const asyncIterable = (async function* filterAsyncData() {
    const items = await getAsyncData();

    for (const item of items) {
        yield item;
    }
})();

const asyncIterable2 = {
    [Symbol.asyncIterator]() {
        return {
            values: null,
            idx: 0,
            async next() {
                if (this.values === null) {
                    this.values = await getAsyncData();
                }

                if (this.idx < this.values.length) {
                    this.idx = this.idx + 1;
                    return Promise.resolve({ value: this.values[this.idx - 1], done: false });
                }

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

async function main() {
    for await (const filteredItem of asyncIterable) {
        console.log(filteredItem);
    }
}

main()

Он не срабатывает, если я использую asyncIterable или asyncIterable2 в функции main, я всегда получаю тот же результат. Как лучше всего определить мою итерацию? Есть ли какие-либо рекомендации относительно того, какой вариант предпочтительнее? Почему?

1 Ответ

2 голосов
/ 14 июля 2020

Это то же самое, что и для синхронных итераторов. : функции генератора намного проще написать и легче исправить, чем реализовать объект итератора вручную. Делайте это только в том случае, если вам нужно какое-то нестандартное поведение, которого нельзя добиться иначе. Благодаря функциям асинхронного генератора, вы даже получаете правильную организацию очереди next звонков бесплатно, что является настоящей головной болью, чтобы получить правильный ответ (ваш asyncIterable2 не справляется с этим 1 ).

Наиболее распространенная реализация итераций - сделать метод Symbol.asyncIterator методом генератора asyn c:

const asyncIterable = {
    async *[Symbol.asyncIterator]() {
         yield* await getAsyncData();
    },
};

1: const it = asyncIterable2[Symbol.asyncIterator](); it.next(); it.next() - без каких-либо await s между ними - будет звоните getAsyncData дважды, потому что this.values == null в обоих звонках

...