Skip to content Skip to sidebar Skip to footer

Problems With Sequelize Promises And Normal Node.js Callbacks

I'm using Sequelize in an application that uses normal node.js style callbacks in most of its code. Sequelize uses promises though, so a lot of code ends up looking something like

Solution 1:

Since sequelize uses Bluebird promises, you should be able to do this:

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

Solution 2:

It seems that there are a few different solutions to this.

First, to clarify the problem I was having with a more detailed example. Here you can see that the .catch handler gets invoked when the error is thrown in the callback, which isn't what I wanted:

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)

Here's the output, where you can see the callback getting invoked twice:

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)

Changing the order of .then .catch

Bergi pointed to When is .then(success, fail) considered an antipattern for promises? which gives the example of calling .catch before .then, and I confirmed that solves the problem:

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)

Here's the output:

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)

Using .nodeify

cassjj also pointed to nodeify, which effectively turns the promises into normal node code:

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

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

Here the output matches the .catch .then example:

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)

I also confirmed that I see the same result even if I add a catch handler:

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

I'm going to go with .nodeify.


Post a Comment for "Problems With Sequelize Promises And Normal Node.js Callbacks"