【问题标题】:How to handle recursive promise rejections?如何处理递归承诺拒绝?
【发布时间】:2017-11-09 08:57:34
【问题描述】:

我有一个关于异步等待代码的概念性问题:这是我的代码中的一个 sn-p:

async function uploadFileBackup(fileId, versionNumber, filePath, sync) {
//...some irrelevant code
 const toReturn = new Promise((accept, reject) => {
    s3.upload(params, async function (err, data) {
      if (err) {
        reject(err)
      } else {
        //here is the relevant code
        file.backupStatus = 'success'
        await file.save()
        accept(data)
      }
    })
  })

  if (sync)
    return toReturn
//...some other irrelevant code
}

现在如果行

等待文件.save()

(在承诺成功时发生)失败,然后我的应用抛出 未处理的承诺拒绝,这正是我的问题。

另外,如果传递的 accept 方法抛出异常,promise 将有一个未处理的拒绝。

我可以自然地用 try catch 块包围 else 语句中的代码,但这无济于事,更糟糕的是,它会误导开发人员,因为他会认为错误来自承诺代码 s3.upload,而该部分将成功,而接受代码将是失败的部分:这肯定会产生不同的后果:

  • s3 上传失败意味着文件没有上传
  • 但是 file.save() 失败意味着只有我们的 db 中的文件状态没有更新,但物理文件在 s3 系统中

这两个错误不能在同一个 try catch 块中处理,但是在 accept 方法中发生的事情也不清楚(关于幕后发生的事情)。最后,在回调-承诺桥中添加 try catch 块使代码和可读性变得复杂

那么在这种情况下最好的做法是什么

【问题讨论】:

  • "如果传递的接受方法抛出异常" - 它永远不会

标签: node.js promise async-await


【解决方案1】:

你需要避免Promise constructor antipattern!并且不能将 async 函数作为普通回调传递给忽略返回值的函数,因此不会处理返回的承诺中的错误。

您应该单独使用promisify s3.upload

function upload(params) {
  return new Promise((resolve, reject) => {
    s3.upload(params, (err, data) => {
      if (err) reject(err)
      else resolve(data)
    })
  })
}

然后像这样使用它

async function uploadFileBackup(fileId, versionNumber, filePath, sync) {
  … // some irrelevant code
  if (sync) {
    const result = await upload(params)
    file.backupStatus = 'success'
    await file.save()
    return result
  }
  … // some other irrelevant code
}

此外,您应该避免将 toReturn 创建为仅有条件等待 (if (sync)) 的承诺,否则将创建 forgotten about without handling errors

如果您现在想要处理来自await uploadawait file.save 的错误,您可以将它们包装在try/catchwhatever is appropriate 中。如果你不处理它们,它们将拒绝uploadFileBackup 返回的承诺,需要由它的调用者在某个地方处理,但它们不会导致流浪承诺的未处理拒绝。

【讨论】:

  • 好的,换句话说,你的意思是,resolve 方法永远不应该做一些相关的事情。这意味着我将不得不重复承诺解决之后的逻辑,我无法将该逻辑绑定到调用本身
  • 另外,这个方法可以异步调用,避免阻塞请求,所以提出了参数sync
  • 不确定“解决方法”是什么意思?是的,您传递给s3.upload 的回调应该只解决承诺而不做其他任何事情,所有其他事情都应该发生在then 回调中(或在await 之后)。
  • 您需要重复哪些部分?我在您的问题的代码中看不到任何内容。你想“绑定到调用本身”什么?
  • 那个参数“sync”对我来说没有多大意义——无论你传递什么参数,上传和文件保存总是异步的(拥有函数块确实是一种可怕的做法,甚至更多取决于它的论点之一)。也许您需要显示其余代码(您已标记为“不相关”)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-26
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
  • 2020-03-22
  • 2018-03-31
相关资源
最近更新 更多