JavaScript: Async, Promises & Callbacks

Amitha Perera
5 min readJan 26, 2020

--

JavaScript is single threaded. It can only execute one task at a time. Suppose we have few line of code to execute for various of actions, JavaScript is not going to execute all the line simultaneously. It will run all the steps in sequence, after each other. But this has a downside. What if we have certain operations that take bit longer time to execute. Think about the below line of code.

console.log(‘01’);setTimeout(()=> {console.log('02')}), 1000); 
//this task is taking more time(doesn't matter whether it is ms or seconds) could be HTTP request
console.log(‘03’);

So the second line is blocking the execution of other code lines until set timer is done. So this is what happened if JavaScript treat setTimeout as it would treat all other code blocks. But in most cases we don’t need to wait till this longer taking one is done.

JavaScript and the browse have a solution for this. If it is a longer taking task, can hand it off to the browser by calling the setTimeout function. Since browser is able to use multiple threads it can allocates one for JavaScript and one for other task. Therefore the JavaScript code is not block any more.

Firefox allocate separate thread for each tab and Chrome uses multiprocessing(single process for each tab). Firefox is faster than the Chrome but there is a high possibility to crash firefox than the chrome

But the browser needs a way to communicate back to our JavaScript code. Typical way is callbacks functions. First argument of setTimeout function is a callback functions so once the browser is done with it task this callback functions is the one browser needs to callback with it’s result.

Message Queue, Event Loop and Async code

When JavaScript code started to execute “Stack” which is part of the JavaScript engine is responsible for take care of certain tasks. When stack filled with tasks like setTimeout(Browser APIs) it directly hand those tasks off to the browser. Then stack become empty and can execute next line of JavaScript code. Now the browser is responsible for take care of the uploaded task, in this case it is setTimeout which has callback function as a first argument. When the browser task is done callback functions should be invoke, for this Message Queue is used.

Message queue is provided by the browser and also linked to the JavaScript. Browser register a to do task inside the queue. When the stack is empty, to do task which is in the queue should be executed for that we need to take queue message in to the call stack, for this we use the Event Loop. Event loop also build into the browser or we can say to the host environment. Event loop is always running and check whether the call stack is empty or not and also check whether there are any pending messages in the message queue. If true then it pushes any waiting messages into the call stack. This is what happened behind the seen and pattern of the asynchronous code execution.

Callback hell and Promises

In most cases we have more than one callback nested into each other, then we enter something call Callback hell. These codes can be cumbersome to read and maintain. So this is where JavaScript concept call promises comes to play.

How we can create a promise and user it in our code?

// create Timer function which return a promise
const timer = (timeDuration) => {
const promise = new Promise((resolve, reject) => {
if(timeDuration > 5000){
reject('Error: Time Expired!');
} else {
setTimeout(() => {
resolve('Done!');
},timeDuration);
}
});
return promise;
};
// call the Timer function
timer(2000).then(data => {
console.log(data);
}, error => {
console.log(error);
});

Promise is a class which is built into the JavaScript and take a function as a constructor argument and that function takes two arguments and each argument itself is a function(resolve and reject). When we create a promise, it’s execute it constructor function right away. Inside this function can define anything you want. Must keep remember that you need to execute resolve function and return the promise object, then only can access the “then” when we call the promise. Like above can warp any code block inside a new promise and then resolve and return that promise object. Also can have multiple “then” block if it has multiple promises (promise chaining). What about the catch block?

.then(data => {
console.log('1');
})
.then(postData => {
console.log('2');
})
.catch(err => {
console.log('error');
})
.then(postDataLast => {
console.log('3');
})
.catch(err2 => {
console.log('error 2');
})
// result
1
2
error
3
error 2

The ‘catch’ block does not avoid/skip execution of rest of ‘then’ blocks.

scenario 1: if first promise reject

// result
error
3
error 2

scenario 2: if third promise reject

// result 
1
2
error

Async await

Modern JavaScript also has an alternative solution to ignore catch and then blocks which we have in promises. What just need to do is add async in front of the function name then the function become a promise (return a promise object). Behind the seen it wrap the whole function inside a new promise like we discuss in above. Because of async now we can use await inside the function

async function sample(){
const getTimer = await timer(2000);
console.log(getTimer);
}

Here we missed the error handling, catch block which we had with promises. With async await we use try catch to handle errors.

async function sample(){
try{
const getTimer = await timer(2000);
console.log(getTimer);
} catch(error){
console.log(error);
}
}

Keep remember: Async await increase the readability of JavaScript code and it does not changed the way of JavaScript works.

--

--