Unlike delays created with setTimeout, delays associated with AJAX calls are usually unpredictable, variable, and undesirable. In many cases the speed of the response cannot be feasibly improved, but other tricks can be used to make the process seem faster. Animation is one such trick – while looking at a blank page can be confusing or frustrating, looking at a loading animation (especially an animation that progresses as the data loads) can be oddly satisfying.
In this example I am using using https://jsonplaceholder.typicode.com/ to emulate a situation in which multiple chunks of data are needed for an application. In order to get all the pieces of data as fast as possible, we should make the request to each endpoint right away. To create a user friendly animation, we will update the status of our progress bar every time we receive a response, and trigger our status bar to turn green when we have received the last response.
For those of you with fast connections that can hardly see the bar move before it completes, here is a trick to throttle your internet connection:
- Open the Codepen
- Open Chrome Dev Tools
- Select Network from the top menu
- Check the ‘Disable Cache’ option
- Click the dropdown arrow next to ‘Online’ and try some of the presets like ‘Fast 3G’ or ‘Slow 3G’. When you reload the page things should be noticeably slower.
Jumping into the code
Hopefully you can now see how the progress bar animates as it receives responses and finally turns green once it completes. So how does it work?
For starters, let’s talk about dependancies. I am using Axios, an HTTP client that has become popular as of late. Axios is promise-based, compatible with all major browers, and easy to use. I also am using Babel to be safe about ES6 syntax – Promise.all() is not supported by IE at the time I am writing this.
To begin, compile an array of all the urls that you need to get data from (6 in this example), reach into the DOM to get access to our
#progress-bar element, set the status of the progress bar to 0, and compute the increment that each response should increase this status by (100% / 6 = 16.67%). Optionally, I also saved the current time using
Date.now() – this will allow us to track the time required to load all the data.
With the setup out of the way, map the
urls array to a new array of thenable (promise-based) elements. Iterate over this list using a
forEach() loop to update the progress variable and the DOM when a response is received.
Promise.all() to create a new promise that will resolve when each element of the
calls array is resolved, change the bar to green, and compute the time it took for all the data to load.
A lot of attributes including
left could be used to animate loading of the progress bar. I chose to use
transform: translateX() to move the element and hid the overflow by setting
overflow: hidden on the container.