【问题标题】:Why my try catch block didn't catch the fs.renameSync exception thrown by my Promise.promisifyAll object为什么我的 try catch 块没有捕获我的 Promise.promisifyAll 对象抛出的 fs.renameSync 异常
【发布时间】:2019-04-29 23:12:40
【问题描述】:

代码非常简单。 ks3 is a library 别人开发的。它具有下载文件的启动功能。它使用async.auto 来做到这一点。 我用蓝鸟包裹它Promise.promisifyAll

let ks3p = Promise.promisifyAll(ks3) //ks3 has a start function
try {
    await ks3p.startAsync(param)
} catch (err) {
    //failed to catch fs.renameSync
}

但有时我会收到错误

fs.js:115
    throw err;
    ^
Error: ENOENT: no such file or directory, rename ... -> ...
    at Object.renameSync (fs.js:591:3)

那么为什么 try catch 块没有捕捉到呢?

我进一步检查了the start() implementation。它使用async 来下载文件,但没什么特别的。

async.auto({
    step_1 : ...
    step_2 : ...
    },
    function(err, results) {
    if (err) {
        if (cb) {
            cb(err, results)
        } else {
            fs.unlinkSync(configFile);
            throw err;
        }
    } else {
        fs.unlinkSync(configFile);
        fs.renameSync(downFileName, filePath);
        if (cb) {
            cb(err, {msg:'success',path:filePath}, null);
        }
    }
})

------更新-------

我使用 Promise.promisifyAll 进行包装的部分原因是我不知道如何捕获该错误。我原来的代码是这样的

ks3.download.start(param, (err, result) => {
    //But how do I catch the exception start throw asynchronously ?
    if (err) {
        // error handling 
    } else {
        log(`finished download ${file}`)
    }
    done()
})

------更新2 -------

在进一步挖掘问题后(答案很有帮助)我发现要么我修改了 ks3 代码,要么我必须使用域来捕获异常。我知道domain is deprecated。但是对于这个特定的问题,我发现它是合适的 b/c 我确切地知道是什么导致了问题,而且我目前也没有解决这个问题(b/c 它是一个我无法控制的 npm 模块)。

【问题讨论】:

  • 为什么,你在这里使用异步库?将普通的回调与 Promise 混合在一起真是一团糟。错误处理是一场噩梦(因此是你的问题)。
  • 这是别人的代码(ks3.start 函数),我把它包装在 Promise.promisifyAll 中
  • 但即使我没有用 Promise.promisifyAll 包装 ks3.start 并使用旧的 err 回调,我仍然不知道如何捕获该错误。
  • 这里缺少太多代码。无法遵循代码中的控制流程。根本不知道ks3p.startAsync()async.auto() 有什么关系。抱歉,这里没有足够的信息来了解这是在做什么或按照代码提供建议。另外,根本不知道ks3是什么。在我看来,您应该在回调函数中捕获错误,然后在出现错误时调用 cb(err),但这只是一个疯狂的猜测,因为缺少很多代码。
  • 抱歉给我带来了麻烦。我更新了我的问题,你能再检查一下吗?

标签: node.js error-handling promise try-catch bluebird


【解决方案1】:

请参阅try/catch block not catching async/await error 了解更多上下文,但要回答有关如何在 un-promisified 版本中捕获错误的问题,您必须了解该调用抛出错误时堆栈。

你有

ks3.download.start(param, (err, result) => {
    //But how do I catch the exception start throw asynchronously ?
    if (err) {
        // error handling 
    } else {
        log(`finished download ${file}`)
    }
    done()
})

你应该认为是:

var cb = (err, result) => {
    //But how do I catch the exception start throw asynchronously ?
    if (err) {
        // error handling 
    } else {
        log(`finished download ${file}`)
    }
    done()
});

ks3.download.start(param, cb);

并且是start 本身引发了异常(在它开始调用或安排你的回调之前),所以你需要将 that 调用包装在 try-catch 中:

var cb = (err, result) => {
    //But how do I catch the exception start throw asynchronously ?
    if (err) {
        // error handling 
    } else {
        log(`finished download ${file}`)
    }
    done()
});

try {
    ks3.download.start(param, cb);
} catch (ex) {
    // here.
}

不过,我对async.auto 的异常处理有点怀疑,我担心它可能会运行一些异步抛出的东西而不会捕获错误。特别是,它看起来并不希望 callback 函数永远抛出(请参阅https://github.com/caolan/async/blob/master/lib/auto.js),但如果@987654330 https://github.com/ks3sdk/ks3-nodejs-sdk/blob/master/lib/api/download.js 确实抛出@ 方法失败,就像你看到的那样。

因此,除了 a) 修复 ks3 或 b) 也许 找到一种方法来对 fs 的版本进行猴子修补,ks3 认为永远不会扔。在这两者中,(a) 对我来说听起来要容易得多,我认为它应该看起来像这样:

async.auto({
    // ...
}, 
function(err, results) {
    if (cb) {
        if (err) {
            cb(err);
            return;
        }
        try {
            fs.unlinkSync(configFile);
            fs.renameSync(downFileName, filePath);
        } catch (ex) {
            cb(ex);
            return;
        }
        cb(err, {msg:'success', path:filePath}, null);
    } else {
        // really, i wouldn't even bother fix this case and just make cb required.
    }
})

最重要的是,我假设这是一个错误,即ks3 代码在出现错误时不会删除配置文件并且有一个回调。

【讨论】:

  • 您好,感谢您回答我的问题。按照您的建议,我试图在未承诺的版本中发现错误。但我还是没能抓住它。我添加了另一个捕手 process.on('uncaughtException', function(err) { console.error('Error catch in uncaughtException event:', err) }) 。我发现这是一个捕获 renameSync 错误。
  • 但后来我意识到不会捕获异常 b/c ks3.start() 会异步抛出异常。
  • 您好,我得出的结论是,如果我不修复 k3,我将不得不使用域(据我所知已弃用)来捕获 fs 异常。
  • 祝你好运! Ks3 好像一年多没更新了。你可能不得不分叉它。
猜你喜欢
  • 2010-09-07
  • 1970-01-01
  • 2012-02-24
  • 2021-03-03
  • 2019-07-12
  • 1970-01-01
  • 2016-02-03
  • 1970-01-01
  • 2021-05-13
相关资源
最近更新 更多