bluebird Promise.promisifyAll 可以在 promisify 该对象的函数失败时工作

bluebird Promise.promisifyAll can work while promisify a function of that object fails

我尝试承诺 SFTPWrapper 并解决了这个问题。我不确定它是否发生在其他对象上。

因此,如果我只是 promisify 一个 SFTPWrapper 函数,比如 readdir,bluebird 将具有 unhandledRejection : "Cannot read property 'readdir' of undefined" error。我试了util.promisify,也是同样的错误。

但是如果 promisifyAll(SFTPWrapper) 并且它按预期工作。但这是为什么呢?

----更新-----

我使用的代码,

var Client = require('ssh2').Client
var conn = new Client()
conn.on('ready', function() {
    conn.sftp(async function(err, sftp) {
        if (err) throw err
        try {
          // promisify will have Cannot read property 'readdir' of undefined error
          // both bluebird and util have the error

          //let readdirAsync = Promise.promisify(sftp.readdir)
          let readdirAsync = util.promisify(sftp.readdir)
          list = await readdirAsync(remotePathToList)

         // Promise.promisifyAll(sftp) work
         const sftp2 = Promise.promisifyAll(sftp)
         let list = await sftp2.readdirAsync(toRead)

您没有准确显示错误 "Cannot read property 'readdir' of undefined error" 发生的位置。如果出现在这行代码:

let readdirAsync = util.promisify(sftp.readdir);

那么,问题是sftpundefined。但是,这似乎并不是问题所在,因为您说 const sftp2 = Promise.promisifyAll(sftp) 确实有效。

所以,我猜测问题是在您尝试使用 readdirAsync 时出现的。如果是这种情况,那可能是因为您在执行 let readdirAsync = util.promisify(sftp.readdir) 时丢失了 sftp 父级,这在某种程度上对 readdir 方法的实现很重要。如果确实如此,那么你可以这样做:

let readdirAsync = util.promisify(sftp.readdir).bind(sftp);

确保父对象保持绑定到该方法。因为 Bluebird 的 .promisifyAll() 将新方法放在原始对象上,并且您将它们作为对象上的方法而不是普通函数来调用,所以当您将它们作为 sftp2.readdirAsync() 调用时,这种与原始对象的绑定会自动发生。您也可以这样做:

sftp.readdirAsync = util.promisify(sftp.readdir);

然后,您可以调用 sftp.readdirAsync(...).then(...).catch(...),它们将适当地绑定到 sftp 对象。

P.S。在异步回调中使用 if (err) throw err 永远不是好的错误处理。从字面上看,您永远不应该在异步回调中编写该行代码,除非该异步回调的调用者具有针对该异常的显式处理程序(通常情况并非如此)。它所做的只是将异常抛出到异步遗忘中,没有机会在代码中的其他任何地方进行实际错误处理。