【问题标题】:TypeScript: async generatorTypeScript:异步生成器
【发布时间】:2017-03-17 07:39:14
【问题描述】:

我想要一个这样的功能:

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() 会很慢。

供参考:async generator function proposal

【问题讨论】:

  • 如果您的异步工作在您的生成器工作之前完成,那么您可以让它们具有不同的功能。
  • 重点是生成器本身需要异步(它等待文件系统操作)。
  • 生成器不能是异步的(还)。您发布的代码不需要是异步生成器;它可以分为异步部分和生成器部分。
  • 好吧,在我的具体情况下,iterateDir 将是递归的。对于每个file,都会检测它是否是目录,如果是,则递归调用iterateDir。在这种情况下,我不知道如何拆分异步和生成功能。这是问题的重点..
  • 在这种情况下,我建议使用 observables (Rx.JS)。

标签: javascript typescript async-await generator


【解决方案1】:

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 列表)你可能需要填充Symbol.asyncIterator .见TS2318: Cannot find global type 'AsyncIterableIterator' - async generator

【讨论】:

    【解决方案2】:

    未来值流称为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。这类似于将一次性回调转换为 Promise。

    【讨论】:

    • 不同之处在于iterables是“pull”(调用者请求下一个值)而Observables是“push”(被调用函数确定何时有新值可用并通知调用者)。在 OP 的例子中,他们真的想要一个用生成器函数(pull)解析的 Promise(push)。
    猜你喜欢
    • 2018-01-21
    • 1970-01-01
    • 2019-11-16
    • 2015-08-08
    • 1970-01-01
    • 2017-06-08
    • 2016-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多