Ashlin Ashlin - 3 months ago 15
Javascript Question

Mixing asynchronous functions with synchronous functions?

I have started to play round with Node.js but I am having trouble with asynchronous functions I was able to make a game small game. But the only way I was able to get the asynchronous functions to work with the synchronous functions was to use global variables.

Example

var promptly = require("./promptly"); //needed for input {npm install promptly}
var firstName;
var lastName;

GetFirstName();

function GetFirstName() { //asynchronous function
promptly.prompt('You first name: ', function (err,value) {
firstName = value;
getLastName();
});
}

function getLastName() { //asynchronous function
promptly.prompt('You last name: ', function (err,value) {
lastName = value;
printName();
});
}

function printName() { //synchronous function
console.log(firstName+" "+lastName);
}


This works but my small game with 5 asynchronous function ended with 14 global variable. so my question is what is the right way of doing something like this?

Answer

What @jfriend00 is referring to in his/her comment is that when you define a function, you can define parameters that the function should take.

With that in mind, you could rewrite your code to something like this:

var promptly = require("./promptly"); //needed for input {npm install promptly}


GetFirstName();

function GetFirstName() { //asynchronous function
    promptly.prompt('You first name: ', function (err,firstName) {

        getLastName(firstName);
    });
}

function getLastName(firstName) { //asynchronous function
    promptly.prompt('You last name: ', function (err,lastName) {

        printName(firstName, lastName);
    });
}

function printName(firstName, lastName) { //synchronous function
    console.log(firstName+" "+lastName);
}

Note that each 'step' of the process accepts the result from the previous 'step'.

The async technique you're using is affectionately known as callback hell, as the callbacks (i.e., the functions you're passing to .prompt() as the second argument) tend to nest deeply & quickly become unmanageable.

Javascript these days has a lot of solutions to manage this problem. Once you understand the 'flow' of an async program, I recommend looking into some of the more user-friendly options (take my snippets with a grain of salt, they're just meant to illustrate concepts):

async.js - this library has a lot of great utilities that help you write callbacks in more readable ways:

async.series([
  asyncFunction1(arg, callback) {
    // code
    callback()
  },
  asyncFunction2(arg, callback) {
    // code
    callback()
  },
  asyncFunction3(arg, callback) {
    // code
    callback()
  }
]

Promises - a new feature in Javascript and one already supported by libraries. Under the hood these are interesting, but in practice they simply allow for cleaner code and error handling:

asyncFunction1(args) {
  // code
  return x
}
.then(asyncFunction2(x) {
  // code
  return y
})
.then(asyncFunction3(y) {
  // code
  return z
})

async/await - one of the latest attempts at solving the async code challenge. Personally I haven't used them yet but the examples are interesting.

async function getName() {
  let firstName =  await getFirstName()
  let lastName = await getLastName()
  console.log("Your name is " + firstName + lastName)
}

The last article I linked is definitely worth a read for a good overview of the async challenge. It's not a simple concept to grok, but once it clicks, it's pretty intuitive.