简体   繁体   中英

Running through multiple functions in nodejs / expressjs

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;
}

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);
   });
});

You can also use next() function, this gives you modularity within a route file or among routes files.

Even you needn't worry about async and sync environments.

Do next() from within callback it will execute only after that callback is done or condition fulfilled when that callback is executed.

https://expressjs.com/en/guide/using-middleware.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM