Chris Cirefice
Chris Cirefice

Reputation: 5795

Two Asynchronous Functions in JavaScript (Node.js)

I have a database query (function) which is asynchronous, and as a result I need to use a callback function (no problem with that). However, in Node.js I need to make two separate queries in the same POST function. Both are asynchronous, so I'm having trouble on how to continue with the execution of the POST.

Goal:

  1. Validate form entries for malformations, etc.
  2. Check if username exists in db before saving (must be unique)
  3. Check if email exists in db before saving (must be unique)
  4. Save user if everything checks out, else throw some errors

Normally, I would have something like this (oversimplified):

postSearch = function(req, res, next) {

  var searchCallback = function(err, results) {
    // Do stuff with the results (render page, console log, whatever)
  }
  // This is the db query - async. Passes search results to callback
  defaultSearch(input, searchCallback);
}

Which only has one async query, so only one callback. Normally I would just get the db results and render a page. Now I have to validate some form data, so my POST function looks something like this:

postUser = function(req, res, next) {

  // Some static form validation (works, no issues)

  var usernameExistsCallback = function(err, exists) {
    // Does the username exist? True/false
  }
  // DB query - passes true or false to the callback
  usernameExists(username, usernameExistsCallback);

  var emailExistsCallback = function(err, exists) {
    // Does the email exist? True/false
  }
  // DB query - passes true or false to the callback
  emailExists(email, emailExistsCallback);

  // Check if ALL validation constraints check out, implement error logic
}

The node-postgres module is async, and as a result the queries need callbacks (if I want to return any value, otherwise I can just run the query and disconnect). I have no problem executing both of those queries. I can console.log() the correct results in the callbacks. But now I don't know how to access those results later on in my postUser function.

I've read all about async JavaScript functions, but I've been scratching my head on this one for three hours now trying ridiculous things (like setting global variables [oh my!]) to no avail.

The results I need from these two queries are simply true or false. How can I organize this code to be able to use these results in the postUser function? It seems to me that I need something like a third callback, but I have no clue how to implement something like that. Is it necessary for me to start using async? Would it be a good idea? Nothing in this application is super complex thus far, and I'd like to keep dependencies low <-> it makes sense.

Upvotes: 0

Views: 595

Answers (3)

mynameisdaniil
mynameisdaniil

Reputation: 1156

Simplest way is to nest functions like this:

postUser = function(req, res, next) {
  var emailExistsCallback = function(err, exists) {
    // Does the email exist? True/false

    // Check if ALL validation constraints check out, implement error logic
    next(); // <= you should finally call "next" callback in order to proceed
  }
  var usernameExistsCallback = function(err, exists) {
    // Does the username exist? True/false
    emailExists(email, emailExistsCallback); // <= note this
  }
  usernameExists(username, usernameExistsCallback);
}

Or you can use async, Q, seq or yaff(which is Seq reimplemented). There are number of libs to make your life easier. Better to try them all and decide which one is right for you, your style, requirements and so on.

Upvotes: 1

Greg
Greg

Reputation: 6759

How about this:

postUser = function(req, res, next) {
    // Some static form validation (works, no issues)

    var emailExistsCallback = function(err, exists) {
        // Does the email exist? True/false
        var usernameExistsCallback = function(err, exists) {
            // Does the username exist? True/false
            // DO STUFF HERE
        }
        // DB query - passes true or false to the callback
        usernameExists(username, usernameExistsCallback);
    }
    // DB query - passes true or false to the callback
    emailExists(email, emailExistsCallback);

    // Check if ALL validation constraints check out, implement error logic
}

Upvotes: 1

dandavis
dandavis

Reputation: 16726

you can use a common var to keep track of how many responses you got back. if you have them both, you can then do the stuff that needs them in a third "callback", which i called done():

postUser = function(req, res, next) {

  var hops=0, total=2;

   function done(){
       // do stuff with both username and email
   }

  // Some static form validation (works, no issues)

  var usernameExistsCallback = function(err, exists) {
    if(++hops>=total && exists ){ done(); }
    // Does the username exist? True/false
  }
  // DB query - passes true or false to the callback
  usernameExists(username, usernameExistsCallback);

  var emailExistsCallback = function(err, exists) {
    if(++hops>=total && exists){ done(); }
    // Does the email exist? True/false
  }
  // DB query - passes true or false to the callback
  emailExists(email, emailExistsCallback);

  // Check if ALL validation constraints check out, implement error logic
}

you should probably add error handling as needed by your app, specifically in both of the SQL callbacks, but this is a nice parallel IO ajax pattern that should do what you need.

Upvotes: 0

Related Questions