【问题标题】:How to await for a promise with an inner promise to be resolved?如何等待具有内部承诺的承诺被解决?
【发布时间】:2020-08-14 14:19:31
【问题描述】:

我有一个快速应用程序,希望仅在文件下载和解压缩后返回响应。我的代码如下所示:

function downloadObject() {
  return getObject(...).then((archive) => {
    console.log("Downloaded.");
    fs.writeFileSync(...);
    return decompress(..., function(err) {
      if (err) {
        console.log("Decompression error.");
      } else {
        console.log("Decompressed");
      }
    });
  })
}

app.post("/download", async function (req, res) {
  await downloadObject();
  res.send('ready');
});

它会一直等到文件下载完成,但是会在文件解压缩之前返回响应。我怎样才能让它等待内部承诺也被解决?

【问题讨论】:

  • decompress 长什么样子?

标签: javascript node.js express promise


【解决方案1】:

您实际上是在返回 decompress 函数的结果,但它是一个异步函数,因此返回值并不重要,可能是 undefined

重要的是你传入的回调,其签名可能如下所示:

decompress(..., function(err, result) {
   // Do what you want with the error and the result
})

要使用 promise 而不是回调来实现异步任务,您可以将函数包装在如下所示的 promise 中,并且由于您在另一个 Promise 的 then 中,它会链接

function downloadObject() {
  return getObject(...).then((archive) => {
    console.log("Downloaded.");
    fs.writeFileSync(...);
    return new Promise((resolve, reject) => 
      decompress(..., function(err, result) {
        if (err) {
          reject(err);
        } else {
          resolve(result);
        }
      })
    );
  })
}

这还不是全部,它有效,但我们可以做得更好。 writeFileSync 将阻止您在 Node 中的 IO,我们不希望这样。相反,最好使用writeFile,并且使用 Promise 链接一切都会变得更干净:

function downloadObject() {
  return getObject(...)
    .then((archive) => new Promise((resolve, reject) => {
       fs.writeFile("<filename>", archive?.data, '<file-encoding>', err => {
         if (err) {
           reject(err);
         } else {
           resolve(archive);
         }
       })
    }))
    .then((archive) => new Promise((resolve, reject) => {
      decompress(archive, function(err, result) {
        if (err) {
          reject(err);
        } else {
          resolve(result);
        }
      })
    }));
}

当然是伪代码,我不知道你的archive对象里面是什么,也不知道你的decompress函数的类型签名,但重点是展示如何包装回调-使用 Promises 提供的 reject 函数正确处理 Promises 中的样式函数,将它们链接起来并正确处理错误。

【讨论】:

    【解决方案2】:

    在不太了解decompress 的情况下,我确实注意到它需要回调。 这意味着它本身就是一个异步函数并立即返回。

    使用 util.promisify 将其变成一个常规的 Promise 生成函数:

    async function downloadObject() {
      const archive = await getObject(...);
      console.log("Downloaded.");
      fs.writeFileSync(...); // Or `util.promisify(fs.writeFile)`
      try {
        await util.promisify(decompress)(...);
        console.log("Decompressed");
      } catch (err) {
        console.log("Decompression error.");
      }
    }
    

    这个函数实现了一个现在已删除的答案中提到的常见模式:

    util.promisify = function (f) {
        return function(...args) {
           return new Promise((resolve, reject) => {
              f(...args, (err, result) => { err ? reject(err) : resolve(result); });
           })
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-04-02
      • 2019-04-29
      • 2018-03-19
      • 1970-01-01
      • 2014-03-12
      • 2022-01-17
      • 1970-01-01
      • 2017-04-04
      相关资源
      最近更新 更多