App Masters

App Masters

  • English
  • Português

›Javascript Fundamentals

App Masters - Core

  • Home
  • Content

Backend

  • Node Express
  • Node Worker Threads

Database

  • GraphQL

Javascript Fundamentals

  • Asynchronous Javascript
  • Typescript

Design Patterns

  • Presentational Container Design Pattern

Frontend

  • AMP (Accelerated Mobile Pages)
  • Bubblewrap
  • Gatsby.js
  • Next.js
  • PWA
  • Styled Components

Mobile

  • React Native
  • Store Testing

Server

  • Netlify

Testing

  • Cypress
  • Jest

Design

  • Human Interface
  • Material Design

Tools

  • Bitrise
  • Docker

Asynchronous Javascript

What is it?

A code is Asynchronous when it implements a function that start now and finish it later, and doesn't wait for the result of that function.
Usually, the code is synchronous: that means that every statement has to wait the last one be completed before moving on.

Example of synchronous code

console.log(1)
console.log(2)
console.log(3)
console.log(4)

What this code prints out is:

1
2
3
4

We can see that the output follows the same order that what we write in the example.

Example of asynchronous code

console.log(1)
console.log(2)

setTimeout(() => {
    console.log('callback');
}, 2000);


console.log(3)
console.log(4)

The console output is:

1
2
3
4
callback

Different than what we expected, the program does not wait the return of the timeout to print callback. It continues the program flux till the answear of the callback function is received, and then, print it out.

Callback

Callback is a function fired when and if you get the return result. In the example below, the callback function is fired after 2 seconds, so, is fired when timed out (not if, it will not stop counting except you close the browser page or if the world stops):

setTimeout(() => {
    console.log('callback');
}, 2000);

Callback Hell

What if you want to set different timeouts for each output? I don't know why would you do that, but you can think in a code like this:

setTimeout(() => {
    console.log(1);
}, 3000);

setTimeout(() => {
    console.log(2);
}, 2000);

setTimeout(() => {
    console.log(3);
}, 1000);

The output would be:

3
2
1

No! But it's not what you wanted. You want it to wait 3sec then display 1, wait 2sec then display 2, and finally wait 1sec and display 3. To do so, you need to nest the callbacks:

setTimeout(() => {
    console.log(1);
    setTimeout(() => {
        console.log(2);
        setTimeout(() => {
            console.log(3);
        }, 1000);
    }, 2000);
}, 3000);

For this code, the output is as expected:

1
2
3

But I hope you will agree that the code is really hard to read and understant. That's why these nested callbacks are called callback hell.

Promises

A Promise is a promise (?) that something you requested will happen. That means that you are not sure if a task it's going to be completed or not. Note that the original concept and the javascript concept are pretty much alike.

Let's create an situation:

You are a programmer (if you're here, I'm betting that this is right), and you don't understand promises yet. I'm promising you that you will understand it once you finish reading.

That's a promise, and it has 3 states:

  1. Pending: You don't know if you're going to learn promises
  2. Fullfilled: I'm proud of you and I'm gonna give you a cookie
  3. Rejected: I just lied

Writing this in JavaScript:

let liar = true;

let willLearnPromise = new Promise(
    (resolve, reject) => {
        if(liar){
            let reason = new Error('yeah, I lied');
            reject(reason);
        }else{
            let cookie = "I'm giving you a cookie!";
            resolve(cookie)
        }
    }
)

I believe this code is really simple to understand. But, as a formality, I'll explain the Promise structure.

A Promise takes as a parameter a function, and in that function, we automatically get access to 2 parameters: resolve and reject.
The resolve parameter is used to show that what we expected happened, and the reject parameter is used to show that something went wrong.

The basic Promise structure is:

new Promise((resolve, reject) => { 
    if(everything goes right)
        resolve();

    if(an error ocurred){
        reject();
    }
});

Consuming Promises

To consume our Promise, I'll do the following:

let willLearnPromise = ... //here goes the code seen before

//call our promise

let readContent = () => {
    willLearnPromise
        .then(fullfilled => { console.log(fullfilled) })
        .catch(rejected => { console.log(rejected) })
}

readContent();

When we consume a promise, we use then to get the resolve, and catch, to get the reject.

You can merge the codes and run it in your browser.

If you do, the output will be an error:

Error: yeah, I lied

And no! I'm not a liar. I needed it to be outputed because I don't know how to deliver you a cookie. But I promise I will! So, let's se how.

Chaining Promises

As I said before, I promise you that I'll deliver you a cookie.


let deliverCookie = () => {
    return new Promise((resolve, reject) => {
        resolve("The cookie is on it's way!");
    })
}

Note that we are only resolving the promise. In that cases, the code can be written as below:


let deliverCookie = () => {
    return Promise.resolve("The cookie is on it's way!");
}

The deliverCookie promise can only start after the willLearnPromise.


let liar = false;

let willLearnPromise = ... //here goes the code seen before

let deliverCookie = ... //here goes the code seen before

let readContent = () => {
    willLearnPromise
        .then(deliverCookie)
        .then(fullfilled => { console.log(fullfilled) })
        .catch(rejected => { console.log(rejected) })
}

readContent();

Now, you can run this code and fulfill it with the previous code snippets provided above.

The output will be:

The cookie is on it's way!

And here it is: :cookie:

Async and await

Consider the following code:

fetch('https://jsonplaceholder.typicode.com/todos')
  .then(response => response.json())
  .then(json => console.log(json))
  .catch(err => console.log(err))

In here, we're using Promises chaining. But imagine a scenario where inside the then you have to wait for another promise, that'll generete another then and so on. It would be a lot of chaining.

To avoid that, we can use async to use await keyword inside to chain promises in a better way.


const getTodos = async () => {
    let response = await fetch('https://jsonplaceholder.typicode.com/todos');
    let data = await response.json();
    return data;
}

getTodos().then(data => console.log(data));

First, we put all the code we want inside a function, that will be async. In this case, it'll be getTodos. Rememer that this function returns a promise, so when getTodos is called, we still going to need the then method.

Inside an async function, we can treat our Promises as non blocking code by writing the await keyword. No need for chaining promises and the code get's a lot more readable.

How to learn more

Useful Material

  • https://www.digitalocean.com/community/tutorials/javascript-promises-for-dummies#understanding-promises
  • https://www.luiztools.com.br/post/programacao-assincrona-em-nodejs-callbacks-e-promises/
  • https://javascript.info/async-await
  • https://bigcodenerd.org/resolving-promises-sequentially-javascript/
  • https://www.youtube.com/watch?v=CWjNefiE47Y&list=PL4cUxeGkcC9jx2TTZk3IGWKSbtugYdrlu&index=10
  • https://www.youtube.com/watch?v=vn3tm0quoqE
← GraphQLTypescript →
  • What is it?
    • Example of synchronous code
    • Example of asynchronous code
  • Callback
    • Callback Hell
  • Promises
    • Consuming Promises
    • Chaining Promises
  • Async and await
  • How to learn more
    • Useful Material
App Masters
App masters
Content
More
BlogGitHub
Copyright © 2022 App Masters