Sequelize 承诺和正常 node.js 回调的问题

Problems with Sequelize promises and normal node.js callbacks

我在一个应用程序中使用 Sequelize,该应用程序在其大部分代码中使用正常的 node.js 样式回调。 Sequelize 虽然使用了 promises,所以很多代码最终看起来像这样:

model.find({where: {...}}).then (res) ->
    callback(null, res)
.catch (err) ->
    callback(err)

大多数情况下效果很好,但如果回调中出现问题,则 catch 块将 运行 并再次调用回调,这次使用 err 参数而不是 res。

这在我们使用 expect.js 的单元测试中尤其严重catch 块并使跟踪实际问题变得困难。

为了解决这个问题,我想在当前承诺的范围之外调用回调,并让错误处理程序只处理与 sequelize 直接相关的错误。我该怎么做?

由于 sequelize 使用 Bluebird promises,您应该可以这样做:

model.find({where: {...}).nodeify(callback);

似乎有几种不同的解决方案。

首先,用一个更详细的例子来阐明我遇到的问题。在这里你可以看到当回调中抛出错误时调用了 .catch 处理程序,这不是我想要的:

callback = (err, res) ->
    console.log "Called with err: #{err} res: #{res}"
    throw new Error()

models.User.find({where: {...}}).then (user) ->
    callback(null, user)
.catch (err) ->
    callback(err)

这是输出,您可以在其中看到回调被调用了两次:

Called with err: null res: [object SequelizeInstance:User]
Called with err: Error res: undefined
Unhandled rejection Error
  at callback (./scripts/nodeify_test.coffee:5:15)
  at [object Object].<anonymous> (./scripts/nodeify_test.coffee:10:5)
  at [object Object].tryCatcher (./node_modules/sequelize/node_modules/bluebird/js/main/util.js:24:31)
  at Promise._settlePromiseFromHandler (./node_modules/sequelize/node_modules/bluebird/js/main/promise.js:454:31)
  at Promise._settlePromiseAt (./node_modules/sequelize/node_modules/bluebird/js/main/promise.js:530:18)
  at Promise._settlePromises (./node_modules/sequelize/node_modules/bluebird/js/main/promise.js:646:14)
  at Async._drainQueue (./node_modules/sequelize/node_modules/bluebird/js/main/async.js:177:16)
  at Async._drainQueues (./node_modules/sequelize/node_modules/bluebird/js/main/async.js:187:10)
  at Async.drainQueues (./node_modules/sequelize/node_modules/bluebird/js/main/async.js:15:14)
  at process._tickCallback (node.js:419:13)

正在更改 .then .catch

的顺序

pointed to When is .then(success, fail) considered an antipattern for promises? 给出了在 .then 之前调用 .catch 的例子,我确认这解决了问题:

callback = (err, res) ->
    console.log "Called with err: #{err} res: #{res}"
    throw new Error()

models.User.find({where: {...}}).catch (err) ->
    callback(err)
.then (user) ->
    callback(null, user)

这是输出:

Called with err: null res: [object SequelizeInstance:User]
Unhandled rejection Error
  at callback (./scripts/nodeify_test.coffee:5:15)
  at [object Object].<anonymous> (./scripts/nodeify_test.coffee:10:5)
  at [object Object].tryCatcher (./node_modules/sequelize/node_modules/bluebird/js/main/util.js:24:31)
  at Promise._settlePromiseFromHandler (./node_modules/sequelize/node_modules/bluebird/js/main/promise.js:454:31)
  at Promise._settlePromiseAt (./node_modules/sequelize/node_modules/bluebird/js/main/promise.js:530:18)
  at Promise._settlePromises (./node_modules/sequelize/node_modules/bluebird/js/main/promise.js:646:14)
  at Async._drainQueue (./node_modules/sequelize/node_modules/bluebird/js/main/async.js:177:16)
  at Async._drainQueues (./node_modules/sequelize/node_modules/bluebird/js/main/async.js:187:10)
  at Async.drainQueues (./node_modules/sequelize/node_modules/bluebird/js/main/async.js:15:14)
  at process._tickCallback (node.js:419:13)

使用.nodeify

也指向 nodeify,它有效地将 promise 变成了正常的节点代码:

callback = (err, res) ->
    console.log "Called with err: #{err} res: #{res}"
    throw new Error()

models.User.find({where: {...}}).nodeify callback

此处输出与 .catch .then 示例匹配:

Called with err: null res: [object SequelizeInstance:User]

./node_modules/sequelize/node_modules/bluebird/js/main/async.js:43
        fn = function () { throw arg; };
                                 ^
Error
  at [object Object].callback (./scripts/nodeify_test.coffee:5:15)
  at [object Object].tryCatcher (./node_modules/sequelize/node_modules/bluebird/js/main/util.js:24:31)
  at Promise.successAdapter [as _fulfillmentHandler0] (./node_modules/sequelize/node_modules/bluebird/js/main/nodeify.js:22:30)
  at Promise._settlePromiseAt (./node_modules/sequelize/node_modules/bluebird/js/main/promise.js:528:21)
  at Promise._settlePromises (./node_modules/sequelize/node_modules/bluebird/js/main/promise.js:646:14)
  at Async._drainQueue (./node_modules/sequelize/node_modules/bluebird/js/main/async.js:177:16)
  at Async._drainQueues (./node_modules/sequelize/node_modules/bluebird/js/main/async.js:187:10)
  at Async.drainQueues (./node_modules/sequelize/node_modules/bluebird/js/main/async.js:15:14)
  at process._tickCallback (node.js:419:13)

我还确认,即使我添加了一个捕获处理程序,我也看到了相同的结果:

 models.User.find({where: {...}}).nodeify callback
.catch (err) ->
    callback.call({}, err)

我要和 .nodeify 一起去。