Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Running through multiple functions in nodejs / expressjs

Running through multiple functions in nodejs / expressjs

Problem

How do you run through multiple functions in nodejs / expressjs? In php it's straightforward, call one Function after the other but this callback business in node is confusing, I keep getting errors that a variable isn't defined and such. Here is the basic idea of what I'm doing.

var express = require('express');
var request = require('request');

var app = express();

app.get('/user/:id', function(req, res) {
   var id = req.params.id;

   getInformation(id, function(info) {
      res.send(info);
   });
});

app.listen(3000);

getInformation(id, callback) {
   var qty = makeExternalApiCall();
   var color = secondFunction(id);
   callback({quantity: qty, color: color});
}

makeExternalApiCall() {
   request({uri: 'https://provider.com/api/stuff/'}, function(error, response, body) {
      if (!error && response.statusCode == 200) {
         return body.qty;
      }
   }
}

secondFunction(id) {
   //look up color by id
   var color = "blue";
   return color;
}
Problem courtesy of: Roger

Solution

Running through multiple functions is similar to as it would be in PHP, unless it involves asynchronous functions. An asynchronous callback is a function that can be called at any time, and will not work with the return keyword. Take this callback for example:

var cb = function(arg) {
  console.log(arg);
};

We can pass this callback function into another function, and have that function call cb() from within:

function call(text, callback) {
  callback(text);
};

var txt = 'a string';
call(txt, cb);
console.log('breakpoint');

The example above runs synchronously. Therefore the order of execution is:

call() -> cb()
console.log()

But if we delay the function or add a timer (process.nextTick waits until the callstack of functions is empty, then executes what has been queued):

function call(text, callback) {
  process.nextTick(function() {
    callback(text);
  });
};

And run it again, we get a different execution order because cb() was queued to run after the callstack is empty (right after console.log() runs, it's empty):

call()
console.log()
-> cb()

Most undefined variable errors are caused by accessing a variable before it's set. For example, take the asynchronous function foo().

var data;

foo(function(bar) {
  data = bar;
});
console.log(data);

The callback function(bar) { ... }); may have been called after the console.log(), which means console.log() runs before data is given a value.


As for your specific problem, the request module is asynchronous and uses a callback, so you can't use a return value from within the HTTP request. To get a resultant value from within a callback function, you need to pass it to another callback. Using the return keyword will just stop the function's execution. So change this:

var options = {
  uri: 'https://provider.com/api/stuff/'
};

function makeExternalApiCall() {
  request(options, function(err, res, body) {
    if (!err && res.statusCode == 200) {
       return body.qty;
    }
  }
};

To use a callback:

function makeExternalApiCall(callback) {
  request(options, function(err, res, body) {
    if (!err && res.statusCode == 200) {
       callback(null, body.qty);
    }
  }
};

The function would then be used like so:

makeExternalApiCall(function(err, qty) {
  // here is qty
});

So your routing code might look like this, using nested callbacks:

function getInformation(id, callback) {
  var color = secondFunction(id);
  makeExternalApiCall(function(err, qty) {
    callback({ quantity: qty, color: color });
  });
};

app.get('/user/:id', function(req, res) {
   var id = req.params.id;

   getInformation(id, function(info) {
      res.send(info);
   });
});
Solution courtesy of: hexacyanide

Discussion

View additional discussion.



This post first appeared on Node.js Recipes, please read the originial post: here

Share the post

Running through multiple functions in nodejs / expressjs

×

Subscribe to Node.js Recipes

Get updates delivered right to your inbox!

Thank you for your subscription

×