2

I'm using nodeJS, running express4 framework to create an API. I am using RSVP.js for promises.

worker.getFamilies is called by an external module, not reflected here. The caller expects back an object with results.

Inside worker.getFamilies: - I am querying mongoDB using mongoose (works, we get results back)

  • I am using a promise to get the response object from mongoose when its available. That works.

  • Then I try to return JSON.stringify(results); to the caller of worker.getFamilies and that doesnt work. The caller gets back "undefined". please help.

    var worker = exports;
    var RSVP = require('rsvp');
    
    var getFamiliesFromDB = function(DBconnection){
        var promise = new RSVP.Promise(function(resolve, reject){
            DBconnection.find({} ,{limit:10, sort: [['_id',-1]]}).toArray(function(e, results){ 
                console.log('results:', results);
                resolve(results);
            });   
        });
        return promise;
    }
    
    worker.getFamilies = function(DBConnection){
        getFamiliesFromDB(DBConnection).then(function(results){
    
            //this works
            console.log('here are the fams from the promise', results);
    
            //this doesnt work like i want it to
            return JSON.stringify(results);
        });  
    };
    
quelquecosa
  • 890
  • 1
  • 10
  • 24
  • Can the caller of `worker.getFamilies` accept a promise? If not, you have to force the request to be synchronous. – tcooc Aug 20 '14 at 18:13
  • really? it seems to me the promise is finished by the time we get to return JSON.stringify(results); arent we just returning a 'normal' object by this point? – quelquecosa Aug 20 '14 at 18:17
  • 3
    @quelquecosa [The result of an asynchronous task can't really be `return`ed.](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) Such tasks are event-oriented and the `return` will either act before the event has occurred or, in this case, apply to the callback `function(results)` rather than `worker.getFamilies()`. – Jonathan Lonowski Aug 20 '14 at 18:19
  • Just return inside of `worker.getFamilies`: `return getFamiliesFromDb(...)...` – Zirak Aug 20 '14 at 18:32

3 Answers3

2

Well, for starters your worker.getFamilies function doesn't have a single return statement in it so that's why it returns undefined (this is what JavaScript returns automatically if you don't explicitly return).

Your only return there is inside the .then handler. You need to return the promise:

worker.getFamilies = function(DBConnection){
    // note how we've added a `return` here!
    return getFamiliesFromDB(DBConnection).then(function(results){
        console.log('here are the fams from the promise', results);
        return JSON.stringify(results);
    });  
};

Now that our function returns, we can use its return value:

// from caller site:
worker.getFamilies(dbconn).then(function(jsonResults){
    console.log("Got results!", jsonResults);
});
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
1

As Jonathan Lonowski explained, "The result of an asynchronous task can't really be returned".

There are a couple of solutions for this.

If you have control of the code calling worker.getFamilies. You can modify the code to:

worker.getFamilies = function(DBConnection){
    return getFamiliesFromDB(DBConnection).then(function(results) {
        return JSON.stringify(results);
    });  
};

The make the calling code do this:

worker.getFamilies(DBConnection).then(function(results) {
  console.log('now I can work with', results);
});

If you don't have control over the calling code, it becomes slightly more complicated:

var data;
worker.getFamilies = function() {
    return data;
};
getFamiliesFromDB(DBConnection).then(function(results) {
        data = JSON.stringify(results);
        // Here, start up the code where `worker.getFamilies` is used.
});

Basically, you need to make sure the result is ready before calling the code that needs it.

tcooc
  • 20,629
  • 3
  • 39
  • 57
0

Problem is you are returning from a different context. Refactor getFamilies as follows:

worker.getFamilies = function(DBConnection, callback){
    getFamiliesFromDB(DBConnection).then(function(results){
        callback(JSON.stringify(results));
    });  
};

Since there at least one asynchronous function in the call-stack (in your case - getFamiliesFromDb) you need callbacks (or promises).

In your version, your return statement resolves to the callback function, not getFamilies as you would like to.

Another approach is to transform getFamiliesFromDB to a synchronous call. Either using mongoose API or waiting for the promise to resolve and return it's resolved data.

shturm
  • 857
  • 7
  • 18