In this article we’ll give a run down of what non-blocking is, how it can help you improve performance on your site, and maybe even get that sweet, sweet 100 on performance in Google Lighthouse.
(All examples will be JavaScript/node related)
What is blocking code?
Blocking code is any code that prevents the execution of further code, such as a resource heavy for/while that isn’t being executed asynchronously (we’ll get to what that is a bit later).
A good example of what may constitute blocking code is an operation that accesses an external api or database; doing this in a single thread will force all the other code to wait for that execution to finish, which can be a pain if you need to perform other operations or animations. Blocking code has the potential to noticeably slow your site down if the operation being performed is a lengthy one.
Asynchronous vs synchronous
So you may be asking what is the difference between asynchronous and synchronous ( which I’ll be calling async and sync from now on for brevity).
To put it simply, sync code is like a single lane country road – nobody can overtake, and speed is dictated by the leading vehicle (or in our case, code execution).
Async, on the other hand, is like a motorway which initially only has one lane BUT drivers (operations/functions etc) can add their own lanes, up to an infinite number of lanes (using promises and callbacks), or until your computer catches fire.
So just to recap: sync = single lane country road. Async = magically expanding motorway.
Promises promises
JavaScript promises are a very nice way of firing and chaining async operations.
First, you declare your promise with your function nested inside, or as a callback. Then, you call the promise with .then() appended as the next action to call when the promise is successful, or .catch() to handle errors, and .finally() to be performed regardless of whether or not the execution was successful.
Here’s a simple example;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var simplePromise = new Promise(function(response, error){ //Do some operations response(promiseData); }); //call our shiny new promise simplePromise.then(function(response){ //Do something with our data if our promise resolves with no issues alert(response.messageData); }).catch(function(error){ //Do something with the error if our promises returns an hour console.error(error.code); }).finally(function(){ //Regardless of whether or not the promise succeeds we can do more stuff! someOtherOperation(); }); |
Request animation frame
Now when it comes to JavaScript, I’m not a huge fan of using it for animating. Most animations are fairly simple and can be performed using CSS alone (with keyframes and a bit of checkbox magic).
However, there are definitely uses for firing animations using JavaScript; chaining separate animations, executing based on states or events unknown to CSS. So, when you need to use JS to animate something use the lovely requestAnimationFrame() method! This method takes a callback that contains all your pretty animations as an argument and then makes a very polite request to the window to execute your animations before the next repaint.
This means that the animation will execute at the best possible time and not block up your other operations!
Async script and defer
Finally, let’s talk about the somewhat-related async and defer attribute on script tags.
Adding defer to your script tag loads the contents of the tag after the DOM has finished parsing, meaning the script will have access to all the DOM elements.
This is perfect for non-essential animations or interactions. Async is for tags when they’re availability it not a primary concern (3rd party analytics etc). Using this allows the DOM and other tags to load, and executes the tag whenever it’s ready.
1 2 3 4 5 6 |
<!--Normal script tag --> <script type="text/javascript" src="myscript.js"></script> <!--Defer script tag --> <script type="text/javascript" src="myscript.js" defer></script> <!--Async script tag --> <script type="text/javascript" src="myscript.js" async></script> |
Comparison
Here are two examples of Google Lighthouse performance audits. The first is a site that used all the nice non-blocking methods, including requestAnimationFrame() and async and defer scripts;
and the second, was not;
Conclusion
As publishers and website creators seek to stand out from the crowd, we’re unlikely to see the average page weight significantly reduced any time soon. Making your code as efficient as possible not only helps your users and their bandwidth, but can also help you gain search engine traffic as the major operators tend to reward lean sites over their heavier, slow-loading competitors.
Get it right, and your efforts will receive their maximum potential reward.
Leave a Reply