3

There is something I am not understanding about using deferred promises in node.js using the q module. Here is a set up that illustrates my problem.

var Q = require('q');
var http = require('http');

var url = 'http://www.genenames.org/cgi-bin/download?' +
          'col=gd_hgnc_id&' +
          'col=gd_pub_eg_id&' +
          'status=Approved&' +
          'status_opt=2&' +
          'where=&' +
          'order_by=gd_pub_eg_id&' +
          'format=text&' +
          'limit=&' +
          'submit=submit';

httpGet = function (url) {
    var deferred = Q.defer();
    var body = "";
    http.get(url, function(res) {
        res.on('data', function(chunk) {
            body += chunk;
        });
        res.on('end', function() {
            // WE NEVER GET HERE ...
            console.log(body);
            deferred.resolve(body);
        });
    })
    .on('error', function(err) {
        console.log(err);
    });
    return deferred.promise;
};

var fetchData = function() {
    var deferred = Q.defer();
    httpGet(url)
        .then(deferred.resolve())
        .done();
    return deferred.promise;
};

fetchData()
  .then(function() {
    console.log("I got here before data was downloaded!")
    process.exit(0);
  })
  .catch(function(err) {
    throw(err);
  })
  .done();

In fetchData, the ".then" function gets called before httpGet() is done downloading the data. I do not understand why the .then is executed before the deferred.resolved is called.

If I comment out the deferred.resolve() in fetchData(), then things work as I expect, although then of course the program hangs as the final promise is never fulfilled.

Can someone point out where I am going awry here?

Eric
  • 1,691
  • 16
  • 24
  • 1
    You shouldn't use the [deferrred antipattern](http://stackoverflow.com/q/23803743/1048572) in your `fetchData` function. Why not just `return httpGet(url)`? Also, `.catch(function(err){throw err})` does absolutely nothing, remove it. – Bergi Apr 15 '15 at 23:54
  • Thanks. Good points. I edited the code a bit to clean up, although I left the antipattern you mention since that is where I made the blunder underlying my initial confusion--I leave it as a cautionary tale to others. – Eric Apr 16 '15 at 00:05

1 Answers1

5

You're invoking deferred.resolve immediately. Instead, you want to pass a reference to that function to then, like this:

.then(deferred.resolve)
Interrobang
  • 16,984
  • 3
  • 55
  • 63