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
一起去。
我在一个应用程序中使用 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
的顺序
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
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
一起去。