如何在生成器中使用await?

28

我有一个生成器,其中包括查询数据库等操作,例如:

function* current(db) {
  const items = await db.collection('...').find({ ... });

  for (const item of items)
    if (...) yield item;
}

这不是有效的语法。使用承诺和从then中产生是不可能的。

那我该怎么办?我如何在生成器中使用异步操作?


不行,你不能在ES6和ES7中将async与生成器函数结合使用。 - Bergi
1
当然我不能。但是有可能解决我的问题吗?我想要创建一个依赖于数据库的生成器,从数据库中获取数据是一个异步操作。那么我还有其他选择吗? - rishat
有一些ES提案正在潜伏,以解决如何使这些事情工作的问题。请查看https://github.com/kriskowal/gtor。您将能够手工制作自己的代码,甚至可以使用`await`或`yield`,但我猜这不会太简单或干净。 - Bergi
公平地说,现在在Node 10中有可能创建异步生成器,因此它解决了我所遇到的问题,尽管我现在不确定我的问题是否足够通用和常见。 - rishat
@rm-:我有同样的问题(因此设置了悬赏):等待DB调用的结果,然后从循环中产生结果。 - Dan Dascalescu
2个回答

25

在生成器(也称为异步生成器)中调用await 已经在Node v10+(2018年4月发布)和Chrome自v63以及Firefox v57开始本地支持。

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
}

// async generator
async function* filterAsyncData() {
  const items = await getAsyncData();  // await call in generator
  
  for (const item of items)
    if (item % 2) yield item;
}

(async function main() {
  // for-await syntax
  for await (const filteredItem of filterAsyncData())
    console.log(filteredItem);
  
  // classic iterator syntax
  const fadIt = filterAsyncData();
  while (true) {
    const result = await fadIt.next();  // note await
    if (result.done) break;
    console.log(result.value);
  }
}());

与常规(非异步)生成器相比,在调用.next()之前请记得使用await。或者,自Node v9.2以来,新的for-await-of语法已经可用,并且可以在不使用任何标志的情况下在Node v10中使用。
对于旧版本的node(或Jest),可以使用Babel插件transform-async-generator-functions

1
我想就是这样了! - rishat

-2

您不能将async与生成器函数结合使用。话虽如此,在您的情况下,您很可能不想使用生成器,而是只需拥有一个async函数:

async function current(db) {
  while (true) {
    const latest = await db.collection('messages').findOne({}, {
      sort: {
        timestamp: -1
      }
    });

    return smth;
  }
}

async被转译时,生成器将会为您生成。


我只想指出,在Babel 5中可以这样做。直到最近,Babel 6才支持这一点......我相信是6.17.0版本开始支持的。 - JP Richardson
7
这个 while (true) 循环没有意义,你的函数在第一次迭代中就会 return - Bergi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接