0

I am developing an API that I would to return a promise. The returned promise is composed of several other promises, so I'm using Q.all and/or Q.allSettled. The problem I'm running into is that the code never completes (see test).

I'm expecting to be able to call then/fail/etc on what's being return from addUsers, which is a Q.all or Q.allSettlted

API:

'use strict';

var Q = require('q'),
    mongoose = require('mongoose'),
    User = require('../models/user'),
    _ = require('underscore');


var addUsers = function (users) {
    var promises = _.map(users, function (user) {
        var newUser = new User(user);
        var promise = Q.nbind(newUser.save, newUser);
        return promise();
    });

    return Q.allSettled(promises);
};

module.exports.addUsers = addUsers;

Test:

'use strict';

var kraken = require('kraken-js'),
    express = require('express'),
    request = require('supertest'),
    should = require('chai').should(),
    userApi = require('../lib/userApi'),
    User = require('../models/user');

describe('#userApi tests', function() {

    it('should insert an array of users using the userApi addUsers method', function(done) {
        var users = [];
        var user1 = {
            firstName: 'test1',
            lastName: 'test1',
            password: 'abc123',
            email: 'me1@here.com',
            userName: 'test1'
        };
        var user2 = {
            firstName: 'test2',
            lastName: 'test2',
            password: 'abc123',
            email: 'me2@here.com',
            userName: 'test2'
        };
        var user3 = {
            firstName: 'test3',
            lastName: 'test3',
            password: 'abc123',
            email: 'me3@here.com',
            userName: 'test3'
        };
        users.push(user1);
        users.push(user2);
        users.push(user3);

        //call the api and handle the promise that is returned
        userApi.addUsers(users)
            .then(function(results) {
                should.exist(results);
                //other assumptions here
                done();
            })
            .fail(function(err) {
                done(err);
            })
    });
});
binarygiant
  • 6,362
  • 10
  • 50
  • 73

1 Answers1

0

I'm not a big fan of q. I think is too much magic, so I rather use the native (on node@0.11.x) Promise instead.

But if I understood it right, q.nbind is a wrapper around the node's standard function call.
Maybe I would mimic its behavior using the new promise API as something like this.

promise = function () {
  return new Promise(function(resolve, reject){
    newUser.save(function(err, data){
      if (err) return reject(err)
      resolve(data)

    })
  })
}

I'm assuming that the newUser is a mongoose model, and newUSer.save only call the callback with an error parameter. Since data is undefined, maybe q doesn't call resolve with a falsy value.

I would try running your tests with this version of addUsers instead.

var Promise = Promise || require('es6-promise').Promise // polyfill
, mongoose = require('mongoose')
;

function addUsers (users) {
  return Promise.all(users.map(function(user){
    return new Promise(function(resolve, reject){
      var newUser = new User(user)
      ;
      newUser.save(function(err){
        if (err) return reject(err)
        resolve()
      })
    })
  }))
}

On the side, It looks like that the cool kids are using bluebird this days for their promise fix.
It has great error handling (which is a problem with the native promise) and allow for custom builds.

markuz-gj
  • 219
  • 1
  • 8
  • 1
    No, Q works just the same way - and it does resolve even if you pass no arguments. Your use of native promises actually looks like too less magic, with all those repetitive callbacks. `nbind` is there for a reason :-) – Bergi May 18 '14 at 05:04
  • The reason I nested like this was to avoid creating variables. With this code, I would only save the most inner indentation with `nbind`. – markuz-gj May 18 '14 at 05:15
  • Well, it's still two levels of indentation more than the OP has (`Promise()` and `save()` callbacks). Btw, you could eliminate the `newUser` variable as well. – Bergi May 18 '14 at 05:25