Sequelize promises和普通node.js回调的问题

时间:2015-09-22 05:10:32

标签: javascript node.js promise sequelize.js bluebird

我在一个在大多数代码中使用普通node.js样式回调的应用程序中使用Sequelize。 Sequelize虽然使用了promises,但是很多代码最终看起来像这样:

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

大部分时间都运行良好,但是如果回调中存在问题,那么catch块将运行并再次调用回调,这次是使用err参数而不是res。

这在单元测试中尤其是一个问题,我们正在使用expect.js,它会抛出异常并期望测试运行器捕获它们,但是它们会被sequelize catch块变得混乱,并且很难追查实际问题。

要解决这个问题,我想在当前promise的范围之外调用回调,让错误处理程序只处理与sequ​​elize直接相关的错误。我该怎么做?

2 个答案:

答案 0 :(得分:3)

由于sequelize使用了Bluebird的承诺,你应该可以这样做:

if (Meteor.isServer) {
  Meteor.methods({
    'chargeCard': function(stripeToken, amount) {
      check(stripeToken, Object);
      var stripe = Meteor.npmRequire('stripe')('sk_test_rand');

      stripe.customers.create({
        email: 'a@aol.com'
      }).then(function() {
        return stripe.charges.create({
          amount: amount,
          currency: 'gbp',
          source: stripeToken.id
        });
      }).then(function(err, charge) {
        // New charge created on a new customer
        console.log(err, charge);
      }, function(err) {
        // Deal with an error
        console.log('Card not charge')
      });
    }
  });
}

答案 1 :(得分:0)

似乎有一些不同的解决方案。

首先,用一个更详细的例子来澄清我遇到的问题。在这里你可以看到在回调中抛出错误时会调用.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

的顺序

Bergi指向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

cassjj也指向了nodeify,它有效地将promises转换为普通的节点代码:

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)

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

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

我将选择.nodeify