Intro to Javascript Async Await and Generators on Nodejs

Video Tutorial

Overview

Working with Asynchronous code is very important especially when dealing with events and callback listeners, if you are used to working with promises a lot and fetch data from API and assign callbacks in this case you need to check the new ESNext Async/Await for working with asynchronous functions in a synchronous easy way which makes it even more simpler and easier either to read through your own code or to share it with other developers.

There is also what’s called a generator which basically gives you a full control over which part of a generator function to get executed and which part is not so you would have full control over your functions and promises when to run and when to return, but on the other hand it may feel a little bit inappropriate to work with since it’s covered under a bit more advanced topic.

The tutorial requires you to have a basic knowledge of Promises how they work and the main reason behind using promises over nasty callback stacks, you can take a look on this Tutorial.

Also, make sure to have a basic understanding of javascript and Nodejs since we are going to use Nodejs to run the javascript code.

Lowest versions of Nodejs are not supporting some of the expressions and functions we are going to work so please make to get the latest version.

Async/Await

Most of the time you will need to use the async function with a promise to get the final result out of it either resolved or rejected the output will be one single result and with no registered callbacks or listeners.

Let’s say you have a function called promising that tries to fetch some data from a remote server and fetching this type of data would take some time so we have to tell our code to wait till it finishes getting all the data then continue executing the rest of the code, we usually use callback to handle either data successfully fetched or rejected with a thrown error with promises so we will take a look at both the new and the old way and the major differences.

/*main.js*/
//Imagine it as a fetshing promise function
function promising() {
  return new Promise((resolve, reject) => {
    //We simulate the Remote API by setTimeout for 4seconds.
    setTimeout(() => resolve("You Got What Promised"), 4000);
  });
}
//Old way without Async/Await
const oldGetit = () => {
  promising()
    .then(result => {
      console.log(result);
    })
    .catch(err => {});
  console.log("At the End OLD");
};
//Run it 
oldGetIt();

We are using it the old way with registering callbacks to both the then and the catch handler so each callback will run separately on resolve or reject, we also use the setTimeout function which basically runs a callback after a certain time duration (4secs = 4000ms).

Now let’s run and see the output, it would just wok normally fine.

node ./main.js

$ node ./src/app.js
At the End OLD
You Got What Promised

We started it will wait for 4 seconds before logging the result (“You Got What Promised”).

Let’s take a look on the new ESNext Async/Await version of the above code.

//Using Async Await 
//The same as using: async function getIT()
const getIt = async () => {
  //Wait Till you get Data from promising function then move on to the next lines of code
  let result = await promising();
  //Compiler will stop execution of the code till the promise has returned (resolved or rejected).
  console.log(result);
  console.log("At the End NEW");
};
getIt();

The first thing to notice is async/await code only used on functions plus to declare an async function you use the async keyword before the function keyword or before the braces when declaring an arrow function.

once again run it using node.

node ./main.js

The result will be:

$ node ./src/app.js
You Got What Promised
At the End NEW

If you can clearly notice the differences, at first they may seem identical to how the promise gets resolved and result logged to the console but the only difference is the console logline at the end of both functions, the oldGetIt first displays the At the End OLD message to the console then waits for a four seconds and resolve the promise while the new async/await version when started it waits for the promise to get resolved then afterward it logs the result first then At the End NEW message well, why?

Here is what is actually going on behind the scenes: the old callbacks way reads through the code when it finds the promise callbacks on the then and catch methods it just register them on keep track them but never wait for it it just gonna keep reading and executing code that comes after the promise and when either the promise gets resolve or rejected it grabs the registered callbacks and execute them, but for the async/await versions the compiler is going to stop whenever it finds an await expressions waiting for a promise to finish then it logs the result and logs the END message.

Async/Await: Stops execution until the promise is finished then executes the rest function’s code.

Callbacks (Normal Way): Register callbacks but executes what comes afterward without explecitelly waiting for the promise to finish.

Generators

Generators are special functions that running it doesn’t require a continues function execution, which means you can put break points on your function to stop the execution on a particular breakpoint and you need to explicitly tell it to stop or run to the next point and so on and so forth till the function ends, they basically used to create iterators since you need an explecit control over iterators so a generator can give you what you need.

What you need to learn about generators? : generators a bit advanced topic to cover and they are not quite important as other javascript features such as async/await or promises but still can help you a lot in terms of dealing with custom iterators or promises, you still can ignore this section.

/*To declare a generator you need to use the asterisk before the function name (arrow func cannot be used!)*/
function* myGen(val) {
  //Execute what ever code is before the first yield keyword till the yield
  yield val;
}
//Run the Generators 
let genObj = myGen("space ship");
console.log(genObj);

There are there main things to care about in the above code, first, the asterisk is used to declare a generator just right before the function name, also there is the yield expression inside the function, yield basically means stop and output (Return), so we are outputting the received val argument.

Lastly, when calling a generator function you should expect a specific generator return object since you are using the yield to stop and return also if you try to run the above code it won’t run or better say you won’t see anything gets logged to you let me explain why.

As I told you before a generator is a bunch of breakpoints sat on a function scope and even if you try to call the function normally it won’t run since you need to explicitly tell to move and execute to the next breakpoint which is the (yield expression) and return to you an object that has two properties (value: the value you yielded) and (done: True or False tells you if the generators have reached the end or not).

So we have to call the next function on the return object to run the generator till the first yield, if you have more yield expressions in one function you have to call the next function couple of times (as many as the yield expressions) to execute the whole function code.

let genObj = myGen("space ship");
console.log(genObj.next());

Trying to run the above code with the next function you would get an object logged to you back on the console has the two properties we mentioned, (value & done) value has the value you yield and the done basically tells you if the generators have reached the end of the function or not (all code on the function has been executed).

Let’s say you have two yields and a return statement on generator function who to run those, simply call the next there times, this is how you can benefit from the iterative behavior of a generator and control the execution flow of the function code block as you wish.

function* myGen(val) {
  //Execute what ever code is before the first yield keyword till the yield
  yield val;
  //Execute on the iteration
  yield val + " DONE";
  //Third,
  return val + "FULLY DONE";
}

let genObj = myGen("space ship");
console.log(genObj.next()); ///< First 
console.log(genObj.next()); ///< Second
console.log(genObj.next()); ///< Third

You can use it in many important scenarios but the simple code above is just for making it clear for you and so you can easily understand it.

What’s Next

After this tutorial you should be able to use Async/Await expressions very easily without hassles across your code and for your upcoming project, alongside the generators hopefully, you can create something meaningful with it.

No Comments Yet