Lesson guide
Learning objectives
- Explain the main purpose of Resource loading: onload and onerror in JavaScript.
- Identify the syntax, APIs, or concepts introduced in this lesson.
- Use the examples to predict how JavaScript will behave before you run similar code.
- Connect this topic to nearby lessons in Document and resource loading.
Real-world context
This lesson matters when you need to recognize where Resource loading: onload and onerror fits into real JavaScript programs. The browser allows us to track the loading of external resources – scripts, iframes, pictures and so on.
Key ideas
- Resource loading: onload and onerror is part of the Document and resource loading chapter, so it builds on the surrounding concepts rather than standing alone.
- Read each code example in two passes: first for the result, then for the rule that explains the result.
- When a section compares similar features, focus on the condition that makes you choose one feature over another.
Key terms
- Resource loading: onload and onerror
- Resource
- loading
- onload
- onerror
The browser allows us to track the loading of external resources – scripts, iframes, pictures and so on.
There are two events for it:
onload– successful load,onerror– an error occurred.
Loading a script
Let’s say we need to load a third-party script and call a function that resides there.
We can load it dynamically, like this:
let script = document.createElement('script'); script.src = "my.js"; document.head.append(script);
…But how to run the function that is declared inside that script? We need to wait until the script loads, and only then we can call it.
Please note:
For our own scripts we could use JavaScript modules here, but they are not widely adopted by third-party libraries.
script.onload
The main helper is the load event. It triggers after the script was loaded and executed.
For instance:
let script = document.createElement('script'); // can load any script, 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() { alert( _.VERSION ); };
So in onload we can use script variables, run functions etc.
…And what if the loading failed? For instance, there’s no such script (error 404) or the server is down (unavailable).
script.onerror
Errors that occur during the loading of the script can be tracked in an error event.
For instance, let’s request a script that doesn’t exist:
let script = document.createElement('script'); script.src = "https://example.com/404.js"; // no such script document.head.append(script); script.onerror = function() { alert("Error loading " + this.src); // Error loading https://example.com/404.js };
Please note that we can’t get HTTP error details here. We don’t know if it was an error 404 or 500 or something else. Just that the loading failed.
Important:
Events onload/onerror track only the loading itself.
Errors that may occur during script processing and execution are out of scope for these events. That is: if a script loaded successfully, then onload triggers, even if it has programming errors in it. To track script errors, one can use window.onerror global handler.
Other resources
The load and error events also work for other resources, basically for any resource that has an external src.
For example:
let img = document.createElement('img'); img.src = "https://js.cx/clipart/train.gif"; // (*) img.onload = function() { alert(`Image loaded, size ${img.width}x${img.height}`); }; img.onerror = function() { alert("Error occurred while loading image"); };
There are some notes though:
- Most resources start loading when they are added to the document. But
<img>is an exception. It starts loading when it gets a src(*). - For
<iframe>, theiframe.onloadevent triggers when the iframe loading finished, both for successful load and in case of an error.
That’s for historical reasons.
Crossorigin policy
There’s a rule: scripts from one site can’t access contents of the other site. So, e.g. a script at https://facebook.com can’t read the user’s mailbox at https://gmail.com.
Or, to be more precise, one origin (domain/port/protocol triplet) can’t access the content from another one. So even if we have a subdomain, or just another port, these are different origins with no access to each other.
This rule also affects resources from other domains.
If we’re using a script from another domain, and there’s an error in it, we can’t get error details.
For example, let’s take a script error.js that consists of a single (bad) function call:
// 📁 error.js noSuchFunction();
Now load it from the same site where it’s located:
<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>
We can see a good error report, like this:
Uncaught ReferenceError: noSuchFunction is not defined
https://www.learn-js.online/article/onload-onerror/crossorigin/error.js, 1:1
Now let’s load the same script from another domain:
<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>
The report is different, like this:
Script error.
, 0:0
Details may vary depending on the browser, but the idea is the same: any information about the internals of a script, including error stack traces, is hidden. Exactly because it’s from another domain.
Why do we need error details?
There are many services (and we can build our own) that listen for global errors using window.onerror, save errors and provide an interface to access and analyze them. That’s great, as we can see real errors, triggered by our users. But if a script comes from another origin, then there’s not much information about errors in it, as we’ve just seen.
Similar cross-origin policy (CORS) is enforced for other types of resources as well.
To allow cross-origin access, the <script> tag needs to have the crossorigin attribute, plus the remote server must provide special headers.
There are three levels of cross-origin access:
- No
crossoriginattribute – access prohibited. crossorigin="anonymous"– access allowed if the server responds with the headerAccess-Control-Allow-Originwith*or our origin. Browser does not send authorization information and cookies to remote server.crossorigin="use-credentials"– access allowed if the server sends back the headerAccess-Control-Allow-Originwith our origin andAccess-Control-Allow-Credentials: true. Browser sends authorization information and cookies to remote server.
Please note:
You can read more about cross-origin access in the chapter Fetch: Cross-Origin Requests. It describes the fetch method for network requests, but the policy is exactly the same.
Such thing as “cookies” is out of our current scope, but you can read about them in the chapter Cookies, document.cookie.
In our case, we didn’t have any crossorigin attribute. So the cross-origin access was prohibited. Let’s add it.
We can choose between "anonymous" (no cookies sent, one server-side header needed) and "use-credentials" (sends cookies too, two server-side headers needed).
If we don’t care about cookies, then "anonymous" is the way to go:
<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>
Now, assuming that the server provides an Access-Control-Allow-Origin header, everything’s fine. We have the full error report.
Common mistakes
- Skipping the small examples and then missing the exact rule that Resource loading: onload and onerror depends on.
- Copying code without changing one value at a time to see which part controls the result.
- Treating similar-looking syntax or APIs as interchangeable before checking their edge cases.
Summary
Images <img>, external styles, scripts and other resources provide load and error events to track their loading:
loadtriggers on a successful load,errortriggers on a failed load.
The only exception is <iframe>: for historical reasons it always triggers load, for any load completion, even if the page is not found.
The readystatechange event also works for resources, but is rarely used, because load/error events are simpler.
Predict
Before running this resource-loading check, predict the seven output lines. It models script load, script error, runtime errors after successful loading, image loading, iframe loading, and cross-origin error detail.
Reveal explanation
The output is script loaded:lodash, script error:https://example.com/404.js, runtime:onload still fires, img load:640x480, iframe load:404, window.onerror:Script error., and window.onerror:ReferenceError:full. Script load means the file was loaded and executed, so variables from that library can be used afterward. Script error tells only that loading failed, not whether it was 404 or 500. A programming error inside a successfully loaded script is not a loading error; it belongs to window.onerror. Images fire load when dimensions are known. Iframes historically fire load even for failed page loads. Cross-origin script errors hide details unless the tag uses crossorigin and the server sends matching CORS headers.
Try it
Set serverCors: false in the final reportScriptError call, then predict why the last line becomes the generic Script error. message.
Practice
- Rewrite one example from this lesson without looking at the original, then run it and compare the result.
- Change one input, operator, method call, or option in a code sample and predict what will happen before running it.
- Explain Resource loading: onload and onerror in your own words as if you were reviewing it with another learner.
Keep learning
Continue with Mutation observer when you are ready for the next lesson.