for of 循环如何处理在 javascript 中不可迭代的流

How do for of loops handle streams which aren't iterable in javascript

在节点中,我们可以使用 createReadStream 为文件创建一个读取流,然后基于该流,我们使用 readline.createInterface 获取一个逐行发出数据的新流。

const fileStream = fs.createReadStream(inputFilePath);
const rl = readline.createInterface({
  input: fileStream,
  crlfDelay: Infinity
});

for await (const line of rl) {
  // do something
}

我有两个相关问题:

As I understood, the for(x of y) syntax works with iterables. However streams are not iterable, so how does this work?

for-of 确实需要一个可迭代对象,但该代码使用的是 for-await-of,它需要一个 async 可迭代对象,而不是可迭代对象.这是两个不同(尽管密切相关)的事情。 :-) 可读流 are async iterable,因此您可以对它们使用 for-await-of。请注意,async 可迭代的东西可能不可迭代(我怀疑它们通常不是,因为它们无法同步提供结果)。

I want to ignore the first line emitted on rl.

有几种方法可以做到这一点:

  1. 使用标志
  2. 直接获取async迭代器,调用next

使用标志:

let first = true;
for await (const line of rl) {
    if (first) {
        first = false;
        continue;
    }
    // do something
}

直接使用async迭代器:

let it = rl[Symbol.asyncIterator](); // Get the async iterator
await it.next();                     // Skip the first result -- note `await`
for await (const line of it) {       // Works in most cases because the async
   /* Note `it` not `rl` ^^ */       // *iterator* is also an async *iterable*
                                     // (and that's true of the one you get
                                     // from `readline`)
    // do something
}

迭代器/async迭代器通过return this实现Symbol.iterator/Symbol.asyncIterator很常见,这使得迭代器可迭代 所以它们可以分别与 for-offor-await-of 一起使用。