Playing around with ES7 async functions
In this case study our program must load 3 resources (json files). The requests must to be chained, one after another, logging the output for each request success.
First, let's look how we can accomplish the mission with our old friend Ajax.
The ajax
function is responsible for creating an xhr
object and execute the callback returning the data.
No big deal here, we have done this a lot in the past, right?
// Getting data
ajax('data.json', (data) => {
console.log('AJAX/data >>>', JSON.parse(data));
// Getting users
ajax('users.json', (users) => {
console.log('AJAX/users >>>', JSON.parse(users));
// Getting products
ajax('products.json', (products) => {
console.log('AJAX/products >>>', JSON.parse(products));
});
});
});
Promises are around for a while, and now it is part of the ECMAScript 6º edition.
With promises
we eliminate the pyramid of doom (callback hell), having a much more cleaner code.
Check it out:
// Promises
// Wrap the ajax function to return promises
function requestP(url) {
return new Promise(function(resolve, reject) {
ajax(url, (response) => {
resolve(JSON.parse(response));
});
});
}
// Getting data
requestP('data.json')
.then(function(data){
console.log('Promises/data >>>', data);
});
// Getting users
requestP('users.json')
.then(function(users){
console.log('Promises/users >>>', users);
});
// Getting products
requestP('products.json')
.then(function(products){
console.log('Promises/products >>>', products);
});
With promises, we can easily have parallel execution:
// Parallel operations with promises
// Getting data, users and products
Promise.all([
requestP('data.json'),
requestP('users.json'),
requestP('products.json')
])
.then(function(data) {
console.log('Parallel promises >>>', data);
});
The fetch API is the new Ajax substitute. We have a lot of new features and a very nice promise-based API:
// Promises with the fetch API
// Getting data
fetch('data.json')
.then(function(data) {
return data.json();
})
.then(function(data) {
console.log('Promises+fetch/data >>>', data);
});
// Getting users
fetch('users.json')
.then(function(data) {
return data.json();
})
.then(function(users) {
console.log('Promises+fetch/users >>>', users);
});
// Getting products
fetch('products.json')
.then(function(data){
return data.json();
})
.then(function(products) {
console.log('Promises+fetch/products >>>', products);
});
Generators basically are functions that can have their execution paused. Take a look on what we can do with generators:
// Generators
function request(url) {
ajax(url, (response) => {
iterator.next(JSON.parse(response));
});
}
function *main() {
// Getting data
let data = yield request('data.json');
// Getting users
let users = yield request('users.json');
// Getting products
let products = yield request('products.json');
console.log('Generator/data >>>', data);
console.log('Generator/users >>>', users);
console.log('Generator/products >>>', products);
}
var iterator = main();
iterator.next();
With async functions, we can await
on Promises.
Take a look (awesomeness alert):
(async () => {
// Getting data
let data = await requestP('data.json');
// Getting users
let users = await requestP('users.json');
// Getting products
let products = await requestP('products.json');
console.log('ES7 Async/data >>>', data);
console.log('ES7 Async/users >>>', users);
console.log('ES7 Async/products >>>', products);
})();
With the fetch API:
(async () => {
// Async/await using the fetch API
try {
// Getting data
let data = await fetch('data.json');
// Parsing data
let parsedData = await data.json();
// Getting users
let users = await fetch('users.json');
// Parsing users
let parsedUsers = await users.json();
// Getting products
let products = await fetch('products.json');
// Parsing products
let parsedProducts = await products.json();
console.log('ES7 Async+fetch/data >>>', parsedData);
console.log('ES7 Async+fetch/users >>>', parsedUsers);
console.log('ES7 Async+fetch/products >>>', parsedProducts);
} catch (error) {
console.log(error);
}
})();
Parallel operations with async:
(async () => {
let parallelData = await Promise.all([
requestP('data.json'),
requestP('users.json'),
requestP('products.json')
]);
console.log('Async parallel >>>', parallelData);
})();
Parallel operations with async + fetch (Oh my god this is great!):
(async () => {
let parallelDataFetch = await Promise.all([
(await fetch('data.json')).json(),
(await fetch('users.json')).json(),
(await fetch('products.json')).json()
]);
console.log('Async parallel+fetch >>>', parallelDataFetch);
})();
npm install
grunt
Serve the dist folder, open the /sample/index.html
and check it out you dev-tools console.
http://jakearchibald.com/2014/es7-async-functions/ http://pouchdb.com/2015/03/05/taming-the-async-beast-with-es7.html http://www.sitepoint.com/simplifying-asynchronous-coding-es7-async-functions/