Home 06: Loading data asynchronously
Content
Cancel

06: Loading data asynchronously

You remember from the previous course how the communication in the internet works.

An animal loading a website through a browser, communicating with a server

If we want to load a website, we open our browser, type in the address and the server which hosts the website sends us back the page (please be aware that this is a simplification).

We can do the same with JavaScript. We can load data, for example JSON files, images or gifs.

Asynchronous

You can either load data asynchronously or synchronously. When we load data, we usually load it asynchronous (or async for short).

But what does that mean? It means JavaScript loads the data in the background and sends us an event when the data has finished loading. This way we can continue to run our program. For example, we can continue to draw on the canvas, do calculations or react on user input.

In contrast, if you load data synchronous, our program would wait for the loading to be finished before we would continue running our program. During this time the program would not update anything and would not react on user input.

How to load data in JavaScript

To load data in JavaScript we use AJAX. AJAX is the abbrevation for Asynchronous JavaScript And XML. And despite the name, we can also load other data than XML with this way.

Let’s have a closer look what we need to do, to actually load data with JavaScript.

1. Create a request object

First, we need to create a new request object of the type XMLHttpRequest. Notice the new keyword in front. It tells JavaScript to create a new object. We will have a closer look at this in the next part of the course.

Despite the name, this request object can load all different types of data.

1
const request = new XMLHttpRequest();

2. Telling JavaScript which data we are expecting

Next, we need to tell the request object what type of data we expect to be returned. For this example, we choose json because we want to load a JSON file.

1
2
const request = new XMLHttpRequest();
request.responseType = "json";

Besides json, we have some more response types available:

Response typeDescription
arraybufferAn array of binary raw data that you cannot change
blobA file as an object with raw data, for example images
documentIf the requested files is an SVG, HTML or XML file you’ll get a DOM object back
jsonIf the requested file contains a json string you will get a parsed object back
textWhatever document you request, you get the result as a string (default)

3. Initialising the request

The next step is to initialize our request object, telling it which method we want to use, in our case GET and what the url is we want to load. We will load a JSON file in the same folder as our HTML file called data.json.

If you want to load data from an external website, you would start the url string with https:// followed by the url.

1
2
3
4
5
6
const request = new XMLHttpRequest();
request.responseType = "json";

const method = "GET";
const url = "data.json";
request.open(method, url);

You might wonder what the method does, it tells the server what we want to do, in case of GET we want to retrieve data. But there are more methods to be used. Some of the most common ones I have listed here:

MethodDescription
GETRetrieve data from a server
POSTSubmits usually new data to a server
PUTReplaces an existing object on the server with a new one
PATCHChanges an existing object on the server
DELETEDeletes an object from a server

Here you can learn more about them.

4. Adding an event listener for handling the response

Since loading the data is asynchronous, we need an event listener to be notified when the request object has finished loading. We can use the same addEventListener method as before with the type load. In this case, we will add an anonymous function that prints out the response to the console for us.

1
2
3
4
5
6
7
8
9
10
const request = new XMLHttpRequest();
request.responseType = "json";

const method = "GET";
const url = "data.json";
request.open(method, url);

request.addEventListener("load", function () {
  console.log(request.response);
});

5. Sending the request

The last thing left to do is to send our request to the server.

1
2
3
4
5
6
7
8
9
10
11
12
const request = new XMLHttpRequest();
request.responseType = "json";

const method = "GET";
const url = "data.json";
request.open(method, url);

request.addEventListener("load", function () {
  console.log(request.response);
});

request.send();

After we send the request, our callback function will be called as soon as a result is returned and we can use the data to update our HTML page for example.

You can find more information here.

How to load images in JavaScript

Now that we have learned how to load data in JavaScript, we will have a look at how to load images and display them in HTML. For this example we will first load a JSON file with a random fox image from this API (you will learn what an API is at the end of this chapter): https://randomfox.ca/floof/.

The response from this API will look like this:

1
2
3
4
{
  "image": "https://randomfox.ca/images/42.jpg",
  "link": "https://randomfox.ca/?i=42"
}

Where the image parameter is always a random image of a fox.

1
2
3
4
5
6
7
8
9
10
function loadFox() {
  const url = "https://randomfox.ca/floof/";
  const method = "GET";

  const foxRequest = new XMLHttpRequest();
  foxRequest.responseType = "json";
  foxRequest.open(method, url);
  foxRequest.addEventListener("load", finishedLoadingHandler);
  foxRequest.send();
}

This code should look familiar by now, we are setting the url and the method, we create an object for the request, initializing the request and adding an event listener, before we send the request.

You see that we added the function finishedLoadingHandler as an event listener. Now, lets have a closer look at the finishedLoadingHandler:

1
2
3
4
5
6
7
8
9
10
11
function finishedLoadingHandler(event) {
  const finishedRequest = event.target;
  const response = finishedRequest.response;
  const foxUrl = response.image;

  const imgElement = document.createElement("img");
  imgElement.src = foxUrl;

  const bodyElement = document.querySelector("body");
  bodyElement.appendChild(imgElement);
}

You notice that we get a parameter called event, and the event.target contains the request object. From here we can access the response and this contains the JSON file we have loaded.

Next, we create an img element, set the src parameter to the url of the fox image and append it to the body element of our HTML page.

The only thing that is left to do now is to call the loadFox() function.

If we like, we can get notified when the image has finished loading like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function finishedLoadingHandler(event) {
  const finishedRequest = event.target;
  const response = finishedRequest.response;
  const foxUrl = response.image;

  const imgElement = document.createElement("img");
  imgElement.src = foxUrl;
  imgElement.addEventListener("load", function () {
    console.log("Image finished loading");
  });

  const bodyElement = document.querySelector("body");
  bodyElement.appendChild(imgElement);
}

You see, that HTML helps us with loading of images, no need to load the data by yourself. But of course, you can do it.

A modern approach to load data using fetch

Besides using the XMLHttpRequest object, there is another approach loading data with JavaScript that is supported by all modern browsers. The fetch() method returns a Promise. In simple words, a Promise is an object where you can attach a callback instead of passing it to a function and it will be executed as soon as the promise is resolved.

If you like, you can learn more about promises here.

Let’s have a look at our last example, but with the fetch() method instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
function loadFox() {
  fetch("https://randomfox.ca/floof/")
    .then((response) => response.json())
    .then((response) => {
      const foxUrl = response.image;

      const imgElement = document.createElement("img");
      imgElement.src = foxUrl;

      const bodyElement = document.querySelector("body");
      bodyElement.appendChild(imgElement);
    });
}

It’s less code, since the fetch method does a lot of the work for us. You notice the then method. This is actually used to notice us as soon as the promise is resolved. You note that we have multiple of them that we chain together. First, we parse the response into a JSON object. Next, we can use the JSON response to read out the image value.

There are other ways in JavaScript to work with promises and if you like, you can read about the async-await style.

Common problems

One of the most common error is this: Origin http://127.0.0.1:5500 is not allowed by Access-Control-Allow-Origin.. And this is a problem with CORS. CORS is the abbrevation for Cross-Origin Resource Sharing. A webserver can restrict the content that other websites can load. That means, if you published a website on domain-a.com, you could restrict or allow other websites to load contents from your site, for example domain-b.com can load data, like images, scripts, webfonts.

Sometimes a public server restricts the access to your local address (127.0.0.1) or other domains, so that you cannot load a JSON file or images from the public server. If you publish your page on GitHub Pages it might work.

You can find more information about CORS here.

In contrast to this, most browser follows the SOP, the Same-Origin-Policy. That means, by default your website can only load content from it’s own domain. The CORS policy is a way to soften this strict rule and allow you to load external content.

APIs

API is the abbrevation for Application Programming Interface and it is used to make data and functionality available for other developers.

There are different types of APIs and you already used some of them, like the Web Storage API for example.

Another example of a common API standard is REST-API. REST stands for representational state transfer and is a standard for accessing APIs using HTTP requests.

That means, you can get or retrieve data when you use the GET method. You can create new objects when you use the POST method. And you can delete objects when you use the DELETE method on a HTTP request. We used always the GET method in our examples, because we only want to retrieve data.

There are some Web APIs publicly available, and you can find some here. For example, the actual weather, daily cat facts, random pictures of ducks, and a lot more.

This post is licensed under CC BY 4.0 by the author.
Contents