如何处理递归承诺拒绝?

时间:2017-11-09 08:57:35

标签: node.js promise async-await

我有一个关于异步等待代码的概念性问题:这是我在代码中的代码片段:

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
}

现在如果该行

  

await file.save()

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

此外,如果传递的接受方法抛出异常,则承诺将处于未处理的拒绝状态。

我可以使用 try catch 块自然地围绕else语句中的代码,但这不会有帮助,更糟糕的是,它会误导开发人员,因为他会认为错误来自承诺代码 s3.upload ,而那部分将成功,接受代码将是失败的代码:具有明显不同的后果:

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

这两个错误无法在同一个try catch块中处理,但是捕获accept方法中发生的事情也不清楚(关于场景背后发生了什么)。最后,在回调承诺桥中添加try catch块会使代码和可读性变得复杂化

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

1 个答案:

答案 0 :(得分:3)

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

您应该单独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返回的承诺,并且需要由其来电者处理,但它们不会导致流浪承诺的未处理拒绝。