首页 > 解决方案 > 在另一个 Promise 包裹的流中等待 Promise

问题描述

我有一个包含每行路径的文本文件(可以有空格),例如

C:\Windows\system32
C:\Windows\system33

C:\Windows\DirectX.log

然后我想逐行读取这个文件并确定每行上的文件/目录是否存在。
以下代码可以正常工作:

const path = require("path");
const fs = require("fs-extra");
const readline = require("readline");

const FILE = path.join(__dirname, "file.txt");

(async () => {
  const rl = readline.createInterface({
    input: fs.createReadStream(FILE)
  });

  let lines = [];
  await new Promise((resolve, reject) => {
    rl.on("line", line => line && lines.push(line));
    rl.on("close", () => resolve());
    rl.on("error", err => reject(err));
  });

  for (let line of lines) {
    console.log(line, await fs.pathExists(line));
  }
})();

输出是:

C:\Windows\system32 true
C:\Windows\system33 false
C:\Windows\DirectX.log true

但我想知道一旦我有了路径,我怎么能检查文件/文件夹的存在,即在“线路”事件上。所以我尝试了这个:

const path = require("path");
const fs = require("fs-extra");
const readline = require("readline");

const FILE = path.join(__dirname, "file.txt");

(async () => {
  const rl = readline.createInterface({
    input: fs.createReadStream(FILE)
  });

  await new Promise((resolve, reject) => {
    rl.on("line", async line => line && console.log(line, await fs.pathExists(line)));
    rl.on("close", async () => {
      console.log("close");
      resolve();
    });
    rl.on("error", err => reject(err));
  });

})();

结果是:

C:\Windows\system32 true
C:\Windows\system33 false
close
C:\Windows\DirectX.log true

这并不意外。但是我怎样才能确保resolve()只有在“line”事件的所有承诺都得到解决后才被调用?

标签: javascriptnode.jspromise

解决方案


您可以将所有“行”事件承诺推入一个数组并在“关闭”事件上使用Promise.all(),当给定承诺数组上的所有承诺都被解决时,它会解决,或者一旦数组中的一个承诺被拒绝,就会被拒绝。

像这样的东西:

let promisesArray = [];
let resArray = await new Promise((resolve, reject) => {
    rl.on("line", line => promisesArray.push(fs.pathExists(line).catch( (reason) => { /* Handle Errors */ })));
    rl.on("close", async () => {
      console.log("close");
      return Promise.All(promisesArray);
    });
    rl.on("error", err => reject(err));
  });

并将resArray在 promisesArray 的同一位置保存每个 promise 的结果数组。

编辑:正如Bergi 指出的,Promise.All()当所有的promise 都被触发时,期望被正确调用,但是在这里它们被一个“line”事件触发,这可能会导致一些延迟。因此,如果其中一个在途中被拒绝,则可能Promise.All()尚未调用,因为“关闭”事件尚未到达,因此您将收到“未处理的承诺拒绝”错误,这会使您的程序崩溃。设置承诺时处理错误保证正确的错误处理并且没有崩溃:)


推荐阅读