为什么我的 try catch 块没有捕捉到 Promise.promisifyAll 对象抛出的 fs.renameSync 异常

Why my try catch block didn't catch the fs.renameSync exception thrown by my Promise.promisifyAll object

代码非常简单。 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. It uses 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 模块,我无法控制) .

有关其他上下文,请参阅 ,但要回答有关如何捕获 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 函数永远 throw (参见 https://github.com/caolan/async/blob/master/lib/auto.js), but https://github.com/ks3sdk/ks3-nodejs-sdk/blob/master/lib/api/download.js does throw如果 fs 方法失败,如您所见。

因此,除了 a) 修复 ks3 或 b) 也许 找到一种猴子修补 [=17 版本的方法之外,您无能为力=] 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 代码不会删除配置文件 并且 有一个回调.