Home

Awesome

es7-async

Playing around with ES7 async functions

Case study

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.

Old friend Ajax

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));
		});
	});
});

Not so new friend, Promises

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);
});

New powerful friend, generators

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();

The new awesome beast, async functions

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);
})();

How to run this experiment

npm install
grunt

Serve the dist folder, open the /sample/index.html and check it out you dev-tools console.

References

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/