In the above example there is no functional difference in the code! In the further examples, you can see that without parameters, you must pass empty parenthesis. However if there is only one parameter, you don't need to wrap it in parenthesis. It's best practice to always wrap your parameters in parenthesis just to be safe! Arrow functions implicitly return their value, that means we don't actually need to write return if all we're doing is returning a value.

In and of itself, arrow functions aren't a game changer but as we get into promises you will see just how helpful they are in making your code more readable.

Promises

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value. It's something of a placeholder while your async operation runs, allowing you to wait for the Promise to complete before you try doing anything with the value it gives you.

In my simple example above, you can see that the promise will resolve or reject depending on the value of everything_is_ok. However after the promise is fulfilled, I've chained together some functions.

The then and catch functions are follow-ups to the promise completion and they will be executed in order, unless an error is thrown in which case it will jump to the next catch in the chain.

You can chain these functions together to allow for some simple and easy to read operations on the response of the promise.

Promise.all()

Promise.all() takes an array of promises and will not fulfil the promise until either all of the promises have resolved or one of them has been rejected.

In the above example the two promises are already resolved, therefore the first one that is read resolves the race. However because this runs on a single thread, you won't see that the race is resolved until the stack is empty and it's had a chance to run!

I would advise playing around with Promise.race(), so that you really get to grips with it's behaviour. For instance, it will never resolve if you give it an empty array!

Fetch API

The Fetch API is replacing the age old XMLHttpRequestand the Ajax request wrapper. It also implements promises for you and handles CORS!

This is a very simple and quick example, but for those who are used to writing out an Ajax or XHR you can instantly see how much code isn't there. What a welcome sight!

However because Fetch does so much for us, we need to be a little more guarded with how we handle our response and catch errors. Fetch will only fail if it cannot reach the server, the promise will resolve even if the response is an errenous code! Another common pitfall are opaque responses, which are responses we cannot examine because they are from another origin.

fetch('https://some-web.site/data.json')
.then(response => {
// if the response is opaque we cannot examine it, only serve it
if (response.type === 'opaque') {
return response;
} else if (!response.ok) {
// response.ok is true for any response
// of good header! e.g. 200, 201
throw new Error(response.statusText);
} else {
// this block is where you would cache and serve!
return response;
}
}).catch(error => {
// if you reach this block, it means that the
// origin you tried to reach is offline
console.error(error);
return OFFLINE_404;
});

In this example we guard against both opaque responses and bad responses, this makes our fetch robust to the most common issues encountered in general use of the Fetch API.

Leave a comment

Let me know how you got on with this tutorial, I hope there was no confusion and that you feel ready to really get into building your own progressive web application now. Drop a comment or tweet me!