DEV Community

Cover image for Promises , Callbacks and Async/Await
sv0012
sv0012

Posted on

Promises , Callbacks and Async/Await

Promises,callbacks and async/await are all ways to deal with asynchronous data.Basically asynchronous is when something is going on but you don't want to wait till its done to continue,and you want to continue while it's happening asynchronously rather than synchronous programming where something happens where you wait till it finishes to move on to the next.

Asynchronous programming is very essential to javascript as we often make requests to servers and other places where it can take a few seconds to obtain the data from and if we don't want our program to stall and wait around at these situations,this is where callbacks come in.

With the introduction of ES6 promises were introduced to the language.Promises provide us with a more elegant way to handle asynchronous data.

In ES7,async/await were introduced which deals with promises in an even more elegant way as it looks more like synchronous programming.

Callbacks

A callback is a function passed as an argument to another function.This technique allows a function to call another function.A callback function can run after another function has finished

Let us consider a hypothetical situation where we get posts and create post from a server.Lets use a setTimeout to mimic the time lapse given by the server.

Lets have an array called posts that contains two objects and create a function called getPosts


const posts=[
          {title:'Post One',body:'This is post one'},
          {title:'Post Two',body:'This is post two'}
           ];

function getPosts() {
   setTimeout(()=> {
    let output = '';
    posts.forEach((post,index)=> {
      output += `<li>${post.title}</li>`;
      });
      document.body.innerHTML = output;
      },1000);
   }

getPosts();

Enter fullscreen mode Exit fullscreen mode

The titles are loaded after a second.

Now lets write a createPost function.


const posts=[
          {title:'Post One',body:'This is post one'},
          {title:'Post Two',body:'This is post two'}
           ];

function getPosts() {
   setTimeout(()=> {
    let output = '';
    posts.forEach((post,index)=> {
      output += `<li>${post.title}</li>`;
      });
      document.body.innerHTML = output;
      },1000);
   }

function createPost(post){
   setTimeout(()=> {
    posts.push(post);
    },2000);
}

getPosts();

createPost({title:'Post Three',body:'This is post three'});


Enter fullscreen mode Exit fullscreen mode

But now we don't see the post three because the create post took longer than the getPost which happened in 1 second and by the time post was created the DOM was already painted.

This is where asynchronous programming comes in.Callbacks are one of the ways to do handle this.

Now lets have the createPost also take in a function called callback and call the callback() right after the post is pushed.

Now all we have to do is make the getPosts function the callback.


const posts=[
          {title:'Post One',body:'This is post one'},
          {title:'Post Two',body:'This is post two'}
           ];

function getPosts() {
   setTimeout(()=> {
    let output = '';
    posts.forEach((post,index)=> {
      output += `<li>${post.title}</li>`;
      });
      document.body.innerHTML = output;
      },1000);
   }

function createPost(post,callback){
   setTimeout(()=> {
    posts.push(post);
    callback();
    },2000);
}

createPost({title:'Post Three',body:'This is post three'},getPosts);


Enter fullscreen mode Exit fullscreen mode

Now it will wait 2 seconds and call the entire posts array.

This is a simple implementation to understand how a callback would work.

Promises

A Promise is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.

Considering the same example lets use the same array and getPost function.

But now instead of using a callback to handle the createPost lets use a promise.


const posts=[
          {title:'Post One',body:'This is post one'},
          {title:'Post Two',body:'This is post two'}
           ];

function getPosts() {
   setTimeout(()=> {
    let output = '';
    posts.forEach((post,index)=> {
      output += `<li>${post.title}</li>`;
      });
      document.body.innerHTML = output;
      },1000);
   }

function createPost(post){
  return new Promise((resolve,reject) => { 
     setTimeout(()=> {
    posts.push(post);

    const error = false;

    if(!error) {
     resolve();
    } else {
       reject('Error:Something is wrong');
      }
    },2000);
  });  
}

createPost({title:'Post Three',body:'This is post three'})
.then(getPosts)
.catch(err => console.log(err));

Enter fullscreen mode Exit fullscreen mode

Here instead of running the callback we return a promise.

A promise takes in two parameters :

  • resolve

  • reject

When we want to resolve a promise a successfully,we will call the resolve and when something goes wrong or if there is an error we will call reject.

Now we are not going to pass a callback function and since its returning a promise we will handle it using .then.

This time running it will wait for the timeout and as soon as its done it resolves and once it resolves then it will call the getPosts.

The .catch that is used after the .then is used for error handling if the promise is rejected.

There will be a lot of instances where we might have to deal with promises like when we use axios,fetch,mongoose..etc and most of the time we will just be required to respond to the promise but the above code is a good example on how to create a promise yourself.

Lets take a look at Promise.all

Consider the following promises:


//Promise.all

const promise1 = Promise.resolve('Hello World');
const promise2 = 10;
const promise3 = new Promise((resolve,reject) => setTimeout(resolve,2000,'Goodbye!')
);

Promise.all([promise1,promise2,promise3]).then(values => console.log(values));

Enter fullscreen mode Exit fullscreen mode

The promise.all will return after all the promises are done and it will take time until the longest promise is handled.

Async/Await

These features basically act as syntactic sugar on top of promises, making asynchronous code easier to write and to read afterwards. They make async code look more like old-school synchronous code, so they're well worth learning.

The keyword async before a function makes the function return a promise.The keyword await before a function makes the function wait for a promise.The await keyword can only be used inside an async function.

Place the createPost function inside a new function and prefix the async keyword to the function which will make it asynchronous and before calling createPost prefix it with await and call the getPosts below it.


const posts=[
          {title:'Post One',body:'This is post one'},
          {title:'Post Two',body:'This is post two'}
           ];

function getPosts() {
   setTimeout(()=> {
    let output = '';
    posts.forEach((post,index)=> {
      output += `<li>${post.title}</li>`;
      });
      document.body.innerHTML = output;
      },1000);
   }

function createPost(post){
   setTimeout(()=> {
    posts.push(post);
    },2000);
}



async function init() {
 await createPost({title:'Post Three',body:'This is post three'});
 getPosts();

}

init()


Enter fullscreen mode Exit fullscreen mode

When the init function is called,the await waits till the process is done and once completed it will move to the next and call the getPosts function.

Async/Await with fetch

While we use fetch we will need to handle it with two promises to get the data,in the first promise we need to obtain the JSON format.

Lets use the fake fetch api typicode.


async function fetchUsers() {
 const res = await fetch('https://jsonplaceholder.typicode.com/users')

const data = await res.json();

console.log(data);

}

fetchUsers();

Enter fullscreen mode Exit fullscreen mode

This is how we handle a fetch request using async/await.As you can see its much cleaner than using the .then and its just using one variable after the other

Latest comments (0)