Resource Loading: onload and onerror

The browser helps to track the loading of external resources, such as pictures, scripts and more.

Two primary events are used for that purpose:

  • onload: it supposes a successful load.
  • onerror: it means that an error has occurred.

Loading a Script

Imagine that you should load a third-party script and call a function residing there, as illustrated below:

let script = document.createElement('script');
script.src = "script.js";
document.head.append(script);

To run the function declared inside that script, you should wait until the script loads and only then call it.

Please note, that here you could also use JavaScript modules, but they are not widely used by third-party libraries.

Script.onload

The load event is the main helper here. It occurs once the was already loaded and executed.

Here is an example of the load event:

let script = document.createElement('script');
// any script can be loading from any domain
script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
document.head.append(script);
script.onload = function () {
  // the script generates an auxiliary function
  alert(_); // the function available
};

So, Script variables and run functions can be used in download.

But, the loading may fail. Note that there isn’t any such script (error 404) or the server is done.

Let’s see what happens in such a circumstance.

Script.onerror

Errors occurring during the script loading are tracked in an error event.

Let’s take a look at an example of requesting a non-existing script:

let script = document.createElement('script');
script.src = "https://example.com/404.js"; // no such script
document.head.append(script);

script.onerror = function () {
  alert("Loading an error " + this.src); // Loading an error https://example.com/404.js
};

Please, take into account that the details of the HTTP error are not available here: you can’t know whether it’s an error 404, 500 or anything else.

Another important thing to note: the onload and onerror events track only the loading itself. In other words, errors occurring during the script processing and execution are out of the framework. So, if a script loaded efficiently, then onload happens, even if it includes some programming errors. For tracking the script errors, you can use a global handler called window.onerror.

Other Resources

The load and error events operate for any other resources that have an external src, like in the example below:

let img = document.createElement('img');
img.src = "https://www.w3docs.com/uploads/media/default/0001/05/9eb9e9cba721ba3bb5e653751449173197f2924a.png"; // (*)
img.onload = function () {
  alert(`Image loaded, size ${img.width}x${img.height}`);
};
img.onerror = function () {
  alert("An error occurred while loading image");
};

But, note that several resources begin loading once they are added to the document. The <img> is an exception to the rule. It begins to load after getting a src (*).

For <iframe>, the iframe.onload event occurs once the iframe loading is over. It is both for the efficient load and in case of an error.

Crossorigin policy

Scripts from one site don’t have access to the scripts of the other one. For example, a script at https://www.instagram.com/ can’t read the user’s mailbox at https://gmail.com.

In other words, one origin (domain/port/protocol) can’t access the content of the other one. Even in case of having a subdomain, these are considered different origins.

The rule above affects the resources from other domains, as well. An example of a script error.js consisting of a single (bad) function call is demonstrated below:

//  error.js
noSuchFunction();

If you try loading it from the same site where it’s located, you will have this:

<script>
  window.onerror = function(message, url, line, col, errorObj) {
    alert(`${message}\n${url}, ${line}:${col}`);
  };
</script>
<script src="/article/onload-onerror/crossorigin/error.js"></script>

A good error report can be seen here:

Uncaught ReferenceError: noSuchFunction is not defined
https://javascript.info/article/onload-onerror/crossorigin/error.js, 1:1

The example of loading the same script from another domain will look like this:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      window.onerror = function(message, url, line, col, errorObj) {
        alert(`${message}\n${url}, ${line}:${col}`);
      };
    </script>
    <script src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>
  </body>
</html>

So, there is a different report here:

Script error.
, 0:0

There can be different details, depending on the browser. However, idea remains the same: any information regarding the internals of a script is hidden. The reason is that it is from a different domain.

Still, it is important to know details about errors.

There are services, listening for global errors using window.onerror, saving errors and providing an interface to access and analyze them. So, they make it possible to see real errors, triggered by the users. But, if a script has another origin, no more information will be available.

For allowing cross-origin access, the <script> tag should have the crossorigin attribute. The remote server has to provide specific headers.

Three levels of cross-origin access exist:

  1. No crossorigin attribute - the access is not allowed.
  2. For crossorigin="anonymous" the access is allowed, in case the server responds with the header Access-Control-Allow-Origin including or the origin. Any authorization information or cookies are sent to the remote server.
  3. crossorigin="use-credentials": the access is allowed in case the server sends back the Access-Control-Allow-Origin header with the origin and Access-Control-Allow-Credentials: true. Authorization information and cookies are sent to the remote server.

In case of not having any crossorigin attribute, the access will be prohibited.

So, let’s see how to add it.

You can choose between "anonymous" and "use-credentials". In the event of not caring about the cookies, "anonymous" is the way to go, like this:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      window.onerror = function(message, url, line, col, errorObj) {
        alert(`${message}\n${url}, ${line}:${col}`);
      };
    </script>
    <script crossorigin="anonymous" src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>
  </body>
</html>

Supposing that the server provides Access-Control-Allow-Origin header, the full error report is ready.

Summary

Resources such as scripts, styles, images provide load and error events for tracking their loading:

  • The load event happens on a successful load.
  • The error event occurs on a failed load.

, there is an exception: <iframe>, which only triggers the load, for each load completion, even if the page is not found. For resources, you can also use the readystatechange event. But it is used rarely as the load and error events are simpler and handier.




Do you find this helpful?

Related articles