Erick Ruiz de Chavez

Web Developer, Geek "to the bone", Happy husband.

How to Wait for 2+ Asynchronous Responses on NodeJS (CommonJS Promises)

Have you ever need to wait for several, unrelated asynchronous functions or processes on NodeJS in order to met dependencies of a last request/method/function/etc? I’m really sure you have, and it can be a pain if you do not know how to properly handle it. The worst and common case is having each one of this nested on then previous one.

There is a really easy and common way I’ve seen lately, that is by using Async.js which is not bad, but it is not that good either, mainly cause it is not a standard. If you want (and you should really want!) a standard way to do such tasks (the right way) then you should start using Promises.

From CommonJS:

Promises provide a well-defined interface for interacting with an object that represents the result of an action that is performed asynchronously, and may or may not be finished at any given point in time. By utilizing a standard interface, different components can return promises for asynchronous actions and consumers can utilize the promises in a predictable manner. Promises can also provide the fundamental entity to be leveraged for more syntactically convenient language-level extensions that assist with asynchronicity.

In this example I’ll be demotrating how to use Q (Promises/B proposal by Kris Kowal)  in 3 different use cases: standard functions, NodeJS like functions (callbacks) and finally a simple deferred implementation.

Standard Functions

Just a common JavaScript function that receives 0 or more parameters and returns a value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Module Dependencies
var Q = require('q');

// Some random numbers to play with, and a queue to keep the code readable
var numbers = [Math.random(), Math.random(), Math.random(), Math.random(), Math.random()],
  queue = [];

// A slow useless function to exemplify
function slowFunction(times) {
  var i = 0,
      times = parseInt(1000000000 * times);

  while (i < times) {
      i += 1;
  }

  return times;
}

// For each random number, create a function call and addit to the queue ;)
numbers.forEach(function(number) {
  queue.push(Q.call(slowFunction, this, number));
});

// Q.all: execute an array of 'promises' and 'then' call either a resolve
// callback (fulfilled promises) or reject callback (rejected promises)
Q.all(queue).then(function(ful) {

  // All the results from Q.all are on the argument as an array
  console.log('fulfilled', ful);
}, function(rej) {

  // The first rejected (error thrown) will be here only
  console.log('rejected', rej);
}).fail(function(err) {

  // If something whent wrong, then we catch it here, usually when there is no
  // rejected callback.
  console.log('fail', err);
}).fin(function() {

  // Finally statemen; executed no matter of the above results
  console.log('finally');
});

Output

1
2
fulfilled [ 149412936, 355777001, 942437362, 998285385, 448049797 ]
finally

NodeJS like functions (Inverse of Control)

Most NodeJS callbacks will return 1 or 2 params, first one being the error (if any) and the second the result.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Module Dependencies
var Q = require('q'),
  request = require('request');

// Some URLs to play with, and a queue to keep the code readable
var urls = ['google.com', 'twitter.com', 'facebook.com'],
  queue = [];

// A standard NodeJS function: a parameter and a callback; the callback
// will return error (if any) as first parameter and result as second
// parameter.
function fetchUrl(url, callback) {
  request({
      url: 'http://' + url
  }, function(err, res, body) {
      if (err) {
          callback(err, null);
      } else {
          // For brevity, on this example we are only interested on the headers
          callback(null, res.headers);
      }
  });
}

// For each url, create a function call and addit to the queue ;)
urls.forEach(function(url) {
  queue.push(Q.ncall(fetchUrl, this, url));
});

// Q.all: execute an array of 'promises' and 'then' call either a resolve
// callback (fulfilled promises) or reject callback (rejected promises)
Q.all(queue).then(function(ful) {

  // All the results from Q.all are on the argument as an array
  console.log('fulfilled', ful);
}, function(rej) {

  // The first rejected (error thrown) will be here only
  console.log('rejected', rej);
}).fail(function(err) {

  // If something whent wrong, then we catch it here, usually when there is no
  // rejected callback.
  console.log('fail', err);
}).fin(function() {

  // Finally statemen; executed no matter of the above results
  console.log('finally');
});

Output (Omitted in sake of brevity)

1
2
fulfilled [ { ... }, { ... }, { ... } ]
finally

Deferred

On a previous post I exemplified how to use jQuery’s When which is the same concept of Promise. This time this is the NodeJS version of a Promise.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Module Dependencies
var Q = require('q'),
  request = require('request');

// Some URLs to play with, and a queue to keep the code readable
var urls = ['google.com', 'twitter.com', 'facebook.com'],
  queue = [];

// A standard NodeJS function: a parameter and a callback; the callback
// will return error (if any) as first parameter and result as second
// parameter.
function fetchUrl(url) {
  // The 'deferred' object, base of the Promises proposal on CommonJS
  var deferred = Q.defer();

  request({
      url: 'http://' + url
  }, function(err, res, body) {
      if (err) {
          // An error? Reject the promise
          deferred.reject(err);
      } else {
          // Success! Resolve the promise
          // For brevity, on this example we are only interested on the headers
          deferred.resolve(res.headers);
      }
  });

  // Return only the promise which will allow the usage of 'when' and 'then'
  // among others
  return deferred.promise;
}

// For each url, create a function call and addit to the queue ;)
urls.forEach(function(url) {
  queue.push(fetchUrl(url));
});

// Q.all: execute an array of 'promises' and 'then' call either a resolve
// callback (fulfilled promises) or reject callback (rejected promises)
Q.all(queue).then(function(ful) {

  // All the results from Q.all are on the argument as an array
  console.log('fulfilled', ful);
}, function(rej) {

  // The first rejected (error thrown) will be here only
  console.log('rejected', rej);
}).fail(function(err) {

  // If something whent wrong, then we catch it here, usually when there is no
  // rejected callback.
  console.log('fail', err);
}).fin(function() {

  // Finally statemen; executed no matter of the above results
  console.log('finally');
});

Output (Omitted in sake of brevity)

1
2
fulfilled [ { ... }, { ... }, { ... } ]
finally

Hopefully with this 3 examples you now know a different, standard, clean and elegant way to solve those more than common situations in NodeJS (and also on the browser if you do not use jQuery).

Questions? Comments? :)

Comments