使用javascript的Symbol.asyncIterator来等待循环

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用javascript的Symbol.asyncIterator来等待循环相关的知识,希望对你有一定的参考价值。

我想了解javascriptSymbol.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并在同一个对象上插入一个键Symbol.asyncIterator并为其分配一个名为test的函数,它返回一个Promise。然后我使用for await of循环迭代函数将返回的所有值。

我做错了什么?

PS:我在节点版本10.13.0和最新版本的Chrome

答案

要成为有效的asyncIterator,你的test函数必须返回一个带有next方法的对象,该方法返回带有valuedone属性的结果对象的promise。 (从技术上讲,value是可选的,如果它的值是undefineddone是可选的,如果它的值是false,但是......)

您可以通过以下几种方式实现这一目标:

  1. 完全手动(笨拙,特别是如果你想要正确的原型)
  2. 半手动(稍微不那么尴尬,但仍然难以获得正确的原型)
  3. 使用异步生成器功能(最简单)

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

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))
另一答案

test函数不能返回一个promise,而是一个Iterator(一个带有next()的对象)方法,该方法必须返回一个Promise(使它成为一个异步迭代器)并且Promise必须解析为包含value的对象和一个done键:

function test() 
   return 
     next() 
       return Promise.resolve( value: "test", done: false );
     
   ;

现在虽然有效,但它还没那么有用。但是,您可以使用异步生成器函数创建相同的行为:

  async function* test() 
    await Promise.resolve();
    yield "test";
  

或者在你的情况下:

async function* test() 
  for(let i = 0; i < 10; i++) 
    if(i > 5) 
      await Promise.resolve();
      yield `Greater than 5: ($i)`;
    else 
      await Promise.resolve();
      yield `Less than 5: ($i)`;
    
  

另一答案

你应该使test成为async生成器函数,而yield而不是return

let a = 


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


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

以上是关于使用javascript的Symbol.asyncIterator来等待循环的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript(js)基础

JavaScript 在HTML中使用 JavaScript

javascript 使用javascript设置选定的值

javascript 使用Javascript的后备图像

javascript 使用Javascript的后备图像

javascript 使用