最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - What is the best practice to create an async iterator? Should I use an async generator function or rather use Symbo

programmeradmin1浏览0评论

This code works as expected:

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()

It does not mather if I use asyncIterable or asyncIterable2 in the main function, I always get the same result. What is the best practice to define my iterable? Are there any guidelines about which option is preferred? Why?

This code works as expected:

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()

It does not mather if I use asyncIterable or asyncIterable2 in the main function, I always get the same result. What is the best practice to define my iterable? Are there any guidelines about which option is preferred? Why?

Share Improve this question asked Jul 14, 2020 at 16:18 enanoneenanone 97613 silver badges30 bronze badges 2
  • 1 In this particular case, you actually should be doing for (const filteredItem of await getAsyncData()) { instead of using async iterators/iterables at all. – Bergi Commented Jul 14, 2020 at 16:35
  • You are pletely right! But I do need the iterator because I am mocking the return value of an async generator function in a test :) – enanone Commented Jul 14, 2020 at 16:37
Add a ment  | 

1 Answer 1

Reset to default 8

It's the same as for synchronous iterators: generator functions are much easier to write, and easier to get correct, than implementing the iterator object manually. Do this only if you need some non-standard behaviour that cannot be achieved otherwise. With asynchronous generator functions specifically, you even get the proper queueing of next calls for free, which is a real headache to get right (your asyncIterable2 fails this1).

The most mon implementation of iterables is to make the Symbol.asyncIterator method an async generator method:

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

1: const it = asyncIterable2[Symbol.asyncIterator](); it.next(); it.next() - without any awaits in between - will call getAsyncData twice, because this.values == null in both calls

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论