【问题标题】:Error : Callback was already called when using pg-promise with async series错误:使用带有异步系列的 pg-promise 时已经调用了回调
【发布时间】:2017-08-04 20:34:38
【问题描述】:

我无法理解打印的输出为什么要执行此代码:

1 2 未处理的拒绝错误:已调用回调。

查询成功时似乎 then 和 catch 都执行了。

有什么想法吗?

干杯

    async.series([
            function(callback) {
                db.none(query)
                    .then(function () {
                        return callback(null, true);
                    })
                    .catch(function (err) {
                        return callback(err, null);
                    });
            },
            function(callback) {
                db.any(query)
                    .then(function (data) {
                        console.log('1')
                        return callback(null, data);
                    })
                    .catch(function (err) {
                        console.log('2')
                        console.log(err);
                        return callback(err, null);
                    });
            }
        ],
        function(err, results) {
           if (results && !results[1].isEmpty()) {
              // do something
           }
        });

编辑:

TypeError: results[1].isEmpty is not a function

问题似乎来自其余代码,只是一个简单的未定义函数错误,谢谢。

但我还是不明白:为什么这个错误是在第二个查询中而不是在异步查询之外捕获的

【问题讨论】:

  • 您是否尝试过console.log(err) 并查看它是否能让您了解问题所在?
  • 谢谢,我以为我已经做到了,但有时我忘记了最简单的事情:-)
  • 不要将 async.js 与 promise 一起使用!!!
  • 我能问为什么吗?我不得不这样做,因为我正在使用 pg-promise 模块来使用 postgres
  • 因为 Promise 已经包含你需要的所有实用程序,并且试图在它们之上放置回调只会导致诸如此类的错误(并且通常是非常容易出错的代码)。

标签: javascript node.js asynchronous promise pg-promise


【解决方案1】:

你有没有尝试在外部定义你的函数:

function onYourFunction() {
   console.log('Hi function');
}

然后:

.then(onYourFunction)    //-->(onYourFunction without parentheses )

不幸的是我不使用 pg-promise 但我可以建议promise

此时我创建了所有必要的承诺:

function createPromise(currObj) {
return new Promise(function (resolve, reject) {
    currObj.save(function (errSaving, savedObj) {
        if(errSaving){
            console.log("reject!");
            return reject(errSaving, response);
        }

        console.log('currObj:' + currObj);
        return resolve(savedObj);
    });
});

}

然后在级联中:

var allPromiseOs = Promise.all(promise1, promise2, promise3);

【讨论】:

    【解决方案2】:

    会发生这样的事情:

    • callback(null, data).then() 的上下文中被调用;
    • async 注意到这是该系列的最后一项,因此它调用最终处理程序(仍在 .then() 的上下文中);
    • 最终处理程序抛出错误;
    • 因为代码在.then()的上下文中运行,所以promise实现会捕获错误并调用.catch()
    • 再次调用回调

    概念验证:

    const async = require('async');
    
    async.series([
      callback => {
        Promise.resolve().then(() => {
          callback(null);
        }).catch(e => {
          callback(e);
        });
      }
    ], err => {
      throw Error();
    })
    

    【讨论】:

    • @Bergi 如果回调失败,您仍然会得到未处理的拒绝。
    • 是的,虽然我猜这仍然比“Error: Callback was already”好(尤其是因为几乎没有任何回调消费者对此进行检查,甚至 async.js 也只是添加了它,因为错误的行为使许多犯此错误的用户感到困惑)。无论如何,放弃 async.js 可能是最好的解决方案
    【解决方案3】:

    我是pg-promise的作者。

    您永远不应该将async 库与pg-promise 一起使用,这违背了共享/可重用连接的概念。

    通过任务正确使用相同的连接来实现:

    db.task(t => {
        return t.batch([
            t.none(query1),
            t.any(query2)
        ]);
    })
        .then(data => {
            // data[0] = null - result of the first query
            // data[1] = [rows...] - result of the second query
    
            callback(null, data); // this will work, but ill-advised
        })
        .catch(error => {
            callback(error, null); // this will work, but ill-advised
        });
    

    另请参阅:Chaining Queries

    但是,在您的情况下,看起来当您调用成功的callback(null, data) 时,它会引发错误,进而导致它被捕获在以下.catch 部分中。要对此进行测试,您可以像这样更改您的 Promise 处理程序:

        .then(data => {
            callback(null, data);
        }, error => {
            callback(error, null);
        });
    

    它通常应该抛出一个关于 Promise 缺少 .catch 的错误,因为您在 .then 中抛出了一个错误,并且下面没有对应的 .catch 链接,您也可以通过此代码检查:

        .then(data => {
            callback(null, data);
        }, error => {
            callback(error, null);
        })
        .catch(error => {
            // if we are here, it means our callback(null, data) threw an error
        });
    

    P.S. 你真的应该学会正确使用 Promise,并完全避免任何回调。我只提供了一个与你自己一致的示例,但总的来说,将 Promise 转换为回调是一种非常糟糕的编码技术。

    【讨论】:

    • then(… callback …).catch(… callback …) 仍然是错误的。请从您的示例代码中删除它。
    • @Bergi 这就是作者要找的东西,所以它很糟糕,但没有错,因为它会起作用。这就是我在代码示例之后添加注释的原因。尽管我自己很喜欢承诺,但我正在尝试在不说教的情况下对其进行教育:)
    • 我的意思是它确实不起作用。如果一个绑定到回调,至少应该使用.then(res => callback(null, res), err => callback(err)) 而不是catch
    • @Bergi 为什么?我现在不明白。您显示的内容与我所做的相同,除了返回无关紧要的回调结果,并且还根据被认为是反模式的 Bluebird 的作者:github.com/petkaantonov/bluebird/wiki/…
    • 不,.then(res => { callback(null, res) }).catch(err => { callback(err) }) is not identical.then(res => { callback(null, res) }, err => { callback(err) })。我们想要后者(请查看链接的答案)。
    猜你喜欢
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 2014-08-19
    • 1970-01-01
    • 2017-09-15
    • 2018-06-29
    相关资源
    最近更新 更多