JavaScript Resource Loading: onload and onerror
Learn how the onload and onerror events track when images, scripts, and stylesheets finish loading or fail, with runnable examples and fallback patterns.
External resources — images, scripts, stylesheets, iframes — load asynchronously and independently of the JavaScript that requests them. The browser kicks off the download and your code keeps running; the resource may not be ready for milliseconds or seconds. To know when a resource is ready (or that it failed), every loadable element fires two events: load on success and error on failure. This page shows how to use them with the onload / onerror handler properties.
This is closely related to the page-level lifecycle covered in DOMContentLoaded, load, beforeunload, unload, and to the loading strategies in Scripts: async, defer.
Handling Resource Loading with the onload Event
What is the onload Event?
The load event fires on an element when its resource has fully finished downloading and is ready to use. You can listen for it in two equivalent ways:
// 1. Handler property (only one handler allowed)
img.onload = () => { /* ... */ };
// 2. addEventListener (multiple handlers allowed)
img.addEventListener('load', () => { /* ... */ });The property form (onload) is convenient but only stores a single handler — assigning a new one overwrites the old. Prefer addEventListener('load', ...) when more than one piece of code cares about the same resource.
A key gotcha: for an <img>, the load event covers only that one image's bytes. It is not the page-wide window.onload, which waits for all resources. Don't confuse the two.
Example: Displaying an Image After Full Load
To illustrate, consider a scenario where you want to display an image only after it is fully loaded to avoid showing a partial or broken image.
<div>Here you see the w3docs logo when the page is loaded.</div>
<br />
<div id="imageContainer" style="background-color: grey;"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var img = new Image();
img.onload = function() {
document.getElementById('imageContainer').appendChild(img);
};
img.src = 'https://www.w3docs.com/build/images/logo-color-w3.png';
});
</script>This script ensures that the image is appended to the #imageContainer div only after it has completely loaded, enhancing the user experience by preventing the display of an incomplete image.
Set img.onload before img.src. The browser may serve a cached image so fast that loading finishes on the same tick the src is assigned — if the handler isn't attached yet, you'll miss the event entirely.
Utilizing the onerror Event for Error Handling
What is the onerror Event?
The onerror event is essential for robust web development. It triggers when an error occurs during the loading of an external resource, such as a script or an image. This event is crucial for handling errors gracefully and ensuring that the user experience remains uninterrupted.
Example: Error Handling for a Failed Image Load
Consider a scenario where an image fails to load due to a broken link or server issue. Using the onerror event, you can provide a fallback solution or notify the user. In the following example, the broken src triggers the error handler as soon as the page runs, because the image link does not point to a real file.
A resource fires either load or error, never both. So you can attach handlers for each and rely on exactly one running.
<div>If there was no error, you could see an image below. But it's a broken link!</div>
<br />
<div id="imageContainer" style="background-color: grey;"></div>
<script>
const img = new Image();
const imageContainer = document.getElementById('imageContainer');
img.onerror = function() {
imageContainer.innerHTML = 'An error happened.';
};
img.onload = function() {
imageContainer.appendChild(img);
};
img.src = 'https://www.w3docs.com/build/images/broken-link.png';
</script>In this example, if the image fails to load, the container shows a fallback message instead of a broken-image icon, handling the error transparently.
onerror only fires for resource failures — a 404, a blocked request, a DNS error, or a corrupt file. It does not fire if a loaded script throws a runtime exception; that is reported by the global window.onerror / window.addEventListener('error', ...) handler instead.
Example: Loading a Script or Stylesheet
The same pattern applies to <script> and <link> elements. You can create them dynamically and attach onload/onerror handlers:
<script>
function loadScript(url) {
const script = document.createElement('script');
script.src = url;
script.onload = () => console.log('Script loaded successfully');
script.onerror = () => console.error('Failed to load script');
document.head.appendChild(script);
}
loadScript('https://example.com/app.js');
function loadStylesheet(url) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
link.onload = () => console.log('Stylesheet loaded successfully');
link.onerror = () => console.error('Failed to load stylesheet');
document.head.appendChild(link);
}
loadStylesheet('https://example.com/styles.css');
</script>Dynamically created scripts behave like async scripts: they download in parallel and run as soon as they arrive, so load order is not guaranteed. If one script depends on another, chain them inside the first script's onload.
Example: Wrapping load/error in a Promise
For modern code, wrapping the two events in a Promise gives you async/await ergonomics and a single place to handle failure:
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Failed to load: ${src}`));
document.head.append(script);
});
}
// Usage
loadScript('https://example.com/app.js')
.then(() => console.log('Ready to use the script'))
.catch((err) => console.error(err.message));Because load and error are mutually exclusive, the Promise settles exactly once — either resolved or rejected.
Optimizing Web Performance Through Event Handling
Optimizing web performance involves managing resource loading sequences and handling failures gracefully. The onload and onerror events are particularly valuable for dynamic resource injection. Instead of hardcoding all assets in the HTML, you can load non-critical resources on demand. When a resource fails to load, the onerror event triggers, allowing you to implement fallback logic—such as swapping a broken image for a placeholder or retrying a failed script request. By combining these events with progressive rendering, you ensure that critical content appears immediately while secondary assets load in the background, maintaining a smooth user experience even under poor network conditions.
Conclusion
Understanding and implementing the onload and onerror events in JavaScript are fundamental for any web developer looking to improve the reliability and performance of their web applications. By employing these events effectively, developers can ensure that resources are managed efficiently, improving both the performance and user experience of their websites. The examples provided offer a starting point for implementing these techniques in various scenarios, fostering a deeper understanding and mastery of resource loading in JavaScript.