TypeScript:异步生成器

时间:2016-11-03 16:05:42

标签: javascript typescript async-await generator

我想要这样的功能:

export async function* iterateDir(dir: string) {
    let list = await fs.readdir(dir); // fs-promise implementation of readdir
    for (let file of list) {
        yield file;
    }
}

我会用的是:

for (let file in iterateDir(dir)) {
    processFile(file);
}

这不起作用,因为函数不能同时是异步和生成器。

如何构建代码以实现相同的目标?

  1. 如果我将await fs.readdir更改为回调,我假设外部for..of循环不会等待。
  2. 如果我摆脱了生成器并且目录很大,iterateDir()会很慢。
  3. 供参考:async generator function proposal

2 个答案:

答案 0 :(得分:13)

TypeScript 2.3 - tracked issue

支持此功能

它引入了一些新类型,特别是:

interface AsyncIterable<T> {
    [Symbol.asyncIterator](): AsyncIterator<T>;
}

但最重要的是它还引入了for await ... of

for await (const line of readLines(filePath)) {
  console.log(line);
}

其中

async function* readLines(path) {
   //await and yield ...
}

请注意,如果您想尝试此操作,则需要配置typescript以让它知道您具有运行时支持(将“esnext.asynciterable”添加到lib列表)您可能需要填充{ {1}}。见TS2318: Cannot find global type 'AsyncIterableIterator' - async generator

答案 1 :(得分:0)

未来值流称为Observable。所以最自然的是使用像RxJS或most.js这样的库。如果您不想仅使用一次新的复杂库,请使用旧的方法进行回调:

const path = require("path");
const fs = require("mz/fs");

async function listDirectory(dirName, cb, level = 0) {
  for (let fileName of await fs.readdir(dirName)) {
    let absName = path.resolve(dirName, fileName);
    let isDirectory = (await fs.stat(absName)).isDirectory();
    cb({ level, fileName });
    if (isDirectory) {
      await listDirectory(absName, cb, level + 1);
    }
  }
}

listDirectory(".", ({ level, fileName }) => {
  console.log(" ".repeat(level) + fileName);
});

如果您尝试将回调转换为更好的抽象,您迟早会重新发现RxJS。它类似于将一次性回调转换为承诺。