javascript - 使用 javascript 的 Symbol.asyncIterator 和 for await 循环

标签 javascript node.js async-iterator ecmascript-2018

我试图理解 javascript 的 Symbol.asyncIteratorfor await of .我写了一些简单的代码,它抛出一个错误说:

    TypeError: undefined is not a function

在尝试使用 for await (let x of a) 的行上.

我无法理解它的原因。
let a = {}


function test() {
        for(let i=0; i < 10; i++) {
                if(i > 5) {
                        return Promise.resolve(`Greater than 5: (${i})`)
                }else {
                        return Promise.resolve(`Less than 5: (${i})`)
                }
        }
}

a[Symbol.asyncIterator] = test;


async function main() {
        for await (let x of a) { // LINE THAT THROWS AN ERROR
                console.log(x)
        }
}


main()
        .then(r => console.log(r))
        .catch(err => console.log(err))

我创建了一个空对象 a并插入一个 key Symbol.asyncIterator在同一个对象上并为其分配一个名为 test 的函数返回 Promise .然后我使用 for await of循环遍历函数将返回的所有值。

我做错了什么?

PS:我是Node版本10.13.0以及最新版本的 Chrome

最佳答案

要成为有效的 asyncIterator ,您的 test 函数必须返回具有 next 方法的对象,该方法返回具有 valuedone 属性的结果对象的 promise 。 (从技术上讲,如果 value 的值为 undefined ,则 done 是可选的,如果其值为 false ,则 async 是可选的,但是......)

您可以通过以下几种方式做到这一点:

  • 完全手动(尴尬,特别是如果你想要正确的原型(prototype))
  • 半手动(稍微不那么尴尬,但获得正确的原型(prototype)仍然很尴尬)
  • 使用异步生成器函数(最简单)

  • 您可以完全手动完成(这不会尝试获得正确的原型(prototype)):

    function test() {
        let i = -1;
        return {
            next() {
                ++i;
                if (i >= 10) {
                    return Promise.resolve({
                        value: undefined,
                        done: true
                    });
                }
                return Promise.resolve({
                    value: i > 5 ? `Greater than 5: (${i})` : `Less than 5: (${i})`,
                    done: false
                });
            }
        };
    }
    
    let a = {
        [Symbol.asyncIterator]: test
    };
    
    async function main() {
        for await (let x of a) {
            console.log(x)
        }
    }
    
    main()
        .then(r => console.log(r))
        .catch(err => console.log(err))


    您可以半手动编写一个函数,该函数使用 next async 方法返回一个对象(仍然没有尝试获得正确的原型(prototype)):

    function test() {
        let i = -1;
        return {
            async next() {
                ++i;
                if (i >= 10) {
                    return {
                        value: undefined,
                        done: true
                    };
                }
                return {
                    value: i > 5 ? `Greater than 5: (${i})` : `Less than 5: (${i})`,
                    done: false
                };
            }
        };
    }
    
    let a = {
        [Symbol.asyncIterator]: test
    };
    
    async function main() {
        for await (let x of a) {
            console.log(x)
        }
    }
    
    main()
        .then(r => console.log(r))
        .catch(err => console.log(err))


    或者您可以只使用 Symbol.iterator 生成器函数(最简单,并自动获取正确的原型(prototype)):

    async function* test() {
        for (let i = 0; i < 10; ++i) {
            yield i > 5 ? `Greater than 5: (${i})` : `Less than 5: (${i})`;
        }
    }
    
    let a = {
        [Symbol.asyncIterator]: test
    };
    
    async function main() {
        for await (let x of a) {
            console.log(x)
        }
    }
    
    main()
        .then(r => console.log(r))
        .catch(err => console.log(err))



    关于原型(prototype):您从 JavaScript 运行时本身获得的所有异步迭代器都继承自原型(prototype),该原型(prototype)提供了确保迭代器也是可迭代的非常基本的特性(通过让 this 成为返回 next 的函数)。该原型(prototype)没有公开可用的标识符或属性,您必须跳过箍才能获得它:
    const asyncIteratorPrototype =
        Object.getPrototypeOf(
            Object.getPrototypeOf(
                async function*(){}.prototype
            )
        );
    

    然后,您将使用它作为对象的原型(prototype),并使用您返回的 ojit_code 方法:
    return Object.assign(Object.create(asyncIteratorPrototype), {
        next() {
            // ...
        }
    });
    

    关于javascript - 使用 javascript 的 Symbol.asyncIterator 和 for await 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55531247/

    相关文章:

    javascript - 使用正则表达式匹配具有两个此类子字符串的字符串中的第一个子字符串,默认情况下通常匹配最后一个子字符串

    node.js - 基于 ExpressJS token 的应用程序的 Chai 断言

    node.js - Bot Framework WebChat 失败 [405] 不允许使用方法

    javascript - "catch(console.error)"是捕获 Promise 拒绝的有效方法吗?

    typescript - 有没有办法实现 <T>(x : Promise<AsyncIterableIterator<T>>): AsyncIterableIterator<T> in TypeScript?

    javascript - canvas drawImage 第一次不绘制图像

    javascript - 在Angularjs中使用rest api上传图像

    javascript - 为什么我的 javascript 函数不抛出错误?

    python - 联合异步迭代器会发生什么?

    python - Asyncio 在多个 future 到达时生成结果