Tue Feb 14 2017
Paul Shan
A much awaited feature async
await
is available on your browser now (if you’re using chrome 55 or greater). Firefox will start supporting from version 52 an Safari from 10.1. Others will also follow the path.
So, we can say we have entered the era of async
await
and now can handle our asynchronous programs with style :)
Since birth JavaScript was asynchronous and we used to handle things with callbacks. So for long operations; it was like, a callback inside another callback, then another one inside that, then another. Used to look like something like below.
function lotOfAsyncWork() {
request("/api/isLogin", function(response){
var userId = response.loggedInUserId;
request("/api/user/detsils/"+userId, function (response2) {
request("http://github/repos/"+response2.repoName, function (response3) {
paintTheUI(response3, function () {
hideLoader();
});
});
});
});
}
Due to all those ugly callbacks, an english phrase was being attached to JavaScript. That was “callback hell”. The code used to look really ugly. Then people came up with promises which gave the control back to the callee function to execute any callback. Below is the promise based solution of the above snippet.
function fetchCurrentLogin() {
return new Promise(function (resolve, reject) {
request("/api/isLogin", resolve);
});
}
function fetchUserDetails(response) {
return new Promise(function (resolve, reject) {
var userId = response.loggedInUserId;
request("/api/user/detsils/"+userId, resolve);
});
}
function fetchGithubDetails(response1) {
return new Promise(function (resolve, reject) {
request("/api/isLogin", resolve);
});
}
function fetchCurrentLogin(response2) {
return new Promise(function (resolve, reject) {
request("http://github/repos/"+response2.repoName, resolve);
});
}
function lotOfAsyncWork() {
fetchCurrentLogin()
.then(fetchUserDetails)
.then(fetchGithubDetails)
.then(paintTheUI)
.then(hideLoader);
}
Though the promises have resolved the issue of callback hell till a very good extent. But it also created a problem of promise chaining. Since our code is generally modular and different modules communicate with each other; we started creating a promise chain. And it’s another pain to create and return promises again and again.
ES6 came up with the concept of generators in which you can do pause and resume kind of operations. Generators can be used in many other corners too; but that pause feature with yield
was useful to handle asynchronous in some cases.
ES8 came up with async
and await
keywords which can be used to symbolize a function as asynchronous and to wait or pause till the time it is not resolved. This feature is a mixture of promises and generators.
The keyword async
is used to declare a function as async. The syntax is as simple as putting an keyword async
infront of function, which return an AsyncFunction
object.
async function myFunc(){
//function body
}
AsyncFunction object is like a promise. You can use the myFunc().then()
function to execute some statements after your async function is completed fully.
Unlike a promise, an async function doesn’t have any resolve or reject callbacks; rather it waits using the await
keyword just like the following way.
async function myFunc(){
var result = await someAsyncFunction();
return result;
}
You can also use multiple awaits inside a single await function like the following example.
async function myFunc(){
var result1 = await someAsyncFunction();
var result2 = await someOtherAsyncFunction();
return result1 + result2;
}
Once all await
are resolved in an async function, it will be considered as completed. The first async function may have a promise or could be using a promise object and the rest will simply await till the previous one is resolved. See the example below of a promise chain.
function baseAsyncFunctionWithPromise(argument) {
return new Promise((resolve)=>{
setTimeout(() => resolve(100), 10000)
});
}
async function secondAsyncFunction() {
var result = await baseAsyncFunctionWithPromise();
return ++result;
}
async function finalAsyncFunc() {
var result = await secondAsyncFunction();
return ++result;
}
finalAsyncFunc().then((r)=>{
console.log("finalAsyncFunc resolved with value ", r);
});
The above code snippet will finally print “finalAsyncFunc resolved with value 102”.
The rule is, you can not use await
outside any async
function. The immediate parent must be an async and that is the reason why the following code will throw a syntax error.
async function fetchHTML(urls) {
urls.forEach(url => {
// syntax error
const content = await httpGet(url);
console.log(content);
});
console.log("I am tricky");
}
The correct way to do that iteration is as below.
async function fetchHTML(urls) {
urls.forEach(async url => {
const content = await httpGet(url);
console.log(content);
});
console.log("I am tricky");
}
However, If you think that "I am tricky"
will be printed only after all the async calls are resolved, then you are wrong. Rather "I am tricky"
will be printed before any httpGet(url)
is resolved. And that is because no one is awaiting for the async callbacks (the await is only there for the httpGet()).
If you want to achieve the synchronous kind of behavior here, you will probably have to go with for of
, so that you can avoid the callbacks. Below is the code.
async function fetchHTML(urls) {
for (const url of urls) {
const content = await httpGet(url);
console.log(content);
}
console.log("I am tricky. But I will be printed at the end.");
}
JavaScript is a single threaded language and it just can’t afford to block the thread to wait for an asynchronous function to get resolved. But the handling of asynchronous calls using promise or callback are really a little tough to understand. However async
await
gave us the power to make a code which looks like and also executes synchronously, but do not block the main thread. This is the reason to introduce async await; thus the biggest pro.
async function foo() {
throw new Error('Error!');
}
foo();
The code above would have silently throw an error in previous JavaScript ways, but now in majority of the browsers it's no more silent.
A con with async
await
is, it awaits in one after another. Suppose you have a code like below.
async function myAsyncFunc(){
return await asyncTask1() + await asyncTask2();
}
In this code, JavaScript will run asyncTask1() and will wait till it gets resolved. Then it will trigger asyncTask2() and do the similar thing. So if you don’t have any dependency between asyncTask1 & asyncTask2 and both of them can be triggered parallelly; using two awaits will kind of harm your performance. Though you are open to use Promise.all
and await for a single promise returned by that.
SHARE THIS ARTICLE
Thu Mar 10 2016
OAuth authentications are pretty popular now a days and another thing which is popular is JavaScript. This article shows how to plugin google’s oAuth api for authentication in your own node application.Sat Mar 01 2014
This is a continuation of my CSS3 loader snippet collection series. I've provided spinning css3 animation loader in the part 1 of this series and here in part 2, I'm providing various square type loading