如何在JavaScript中使用异步生成器?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (68)

有一个api,它会返回一个光标来获取更多数据。我像这样嘲笑它:

function fetch(n) {
  return Promise.resolve({
    results: [n],
    next: next < 10 && n + 1,
  })
}

我想要做的是弄清楚我如何使用async / await和生成器来与这个api进行交互。

这基本上就是我的原型:

async function* api(url) {
  let result = await fetch(url)
  yield result
  while (result.next) {
    result = await fetch(result.next)
    yield result
  }
}

我的想法是,我应该能够创建一个异步生成器并从该生成器中生成以便遍历游标:

async function main() {
  const gen = api(0)
  const zero = await gen.next()
  console.log(zero.result)
  const one = await gen.next()
  console.log(one.result)
  const rest = await Promise.all([...gen])
  console.log(rest.map(r => r.result))
}

考虑到所有事情,我认为这是处理分页数据的一种非常好的方式,并且能够提取所有数据[...gen]非常酷。

唯一的问题是,它不起作用!Apprently你不能使用asyncfunction*

❯❯❯ node --version
v7.0.0
❯❯❯ node --harmony --harmony-async-await async-generator.js
/Users/chetcorcos/code/async-generator.js:11
async function* api(url) {
              ^
SyntaxError: Unexpected token *
    at Object.exports.runInThisContext (vm.js:76:16)
    at Module._compile (module.js:545:28)
    at Object.Module._extensions..js (module.js:582:10)
    at Module.load (module.js:490:32)
    at tryModuleLoad (module.js:449:12)
    at Function.Module._load (module.js:441:3)
    at Module.runMain (module.js:607:10)
    at run (bootstrap_node.js:382:7)
    at startup (bootstrap_node.js:137:9)
    at bootstrap_node.js:497:3

但我真的觉得这应该是可能的。有一个名为co的流行图书馆,我一直在探索,但我不认为这就是我想要的。

任何想法如何让“异步生成器”的概念起作用?

提问于
用户回答回答于

可以使用Babel插件transform-async-generator-functions执行此操作。

用法是这样的:

const g = async i => [ 1, 2, 3 ]
  .map(x => x * 10 ** i);

const f = async function * () {
  for (let i = 0; i < 10; i++) {
    const xs = await g(i);
    for (const x of xs) {
      yield x;
    }
  }
};

const main = async () => {
  for await (const x of f()) {
    console.log(x);
  }
};

main().catch(e => console.error(e));

这是一个示例回购,展示了如何设置项目。

重要的部分是.babelrc文件:

{
  "presets": [ "env" ], 
  "plugins": [ "transform-async-generator-functions" ]
 }
用户回答回答于

可以将生成器函数作为参数调用而不使用spread元素,Promise.all()接受一个iterable作为yield返回的参数。注意,Promise.all()Promise按顺序解析或拒绝传递的对象,但是返回结果数组的顺序与传递的iterable中的元素的顺序相同。

let api = (value) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(value)
    }, Math.floor(Math.random() * 3500))
  })
};

let values = [1, 2, 3];
let results = [];
let gen = function* gen(fn, props) {
  let i = 0; 
  do {
    yield fn(props[i]).then(res => {console.log(res); return res});
    ++i;
  } while (i < props.length);
}

Promise.all(gen(api, values))
.then(data => console.log("complete:", data))
.catch(err => console.log(err));

扫码关注云+社区

领取腾讯云代金券