catch every script load-complete event with javascript or jQuery
Categories:
Catching Every Script Load-Complete Event in JavaScript and jQuery

Learn how to reliably detect when dynamically loaded scripts have finished executing, ensuring your application logic runs at the correct time.
In web development, dynamically loading JavaScript files is a common practice for improving performance, managing dependencies, or implementing modular architectures. However, knowing precisely when a dynamically loaded script has finished executing can be challenging. This article explores various techniques in both plain JavaScript and jQuery to reliably detect script load-complete events, helping you avoid race conditions and ensure your application behaves as expected.
The Challenge of Dynamic Script Loading
When you add a <script>
tag to the DOM, the browser fetches and executes the script. For static scripts defined directly in your HTML, the execution order is generally predictable. However, when scripts are added dynamically via JavaScript, their loading and execution are asynchronous. This means that code immediately following the script injection might run before the dynamically loaded script has fully parsed and executed, leading to errors if your subsequent code depends on variables or functions defined in the loaded script.
sequenceDiagram participant Browser participant YourScript participant DynamicScript YourScript->>Browser: Create <script> element YourScript->>Browser: Append <script> to DOM Browser->>DynamicScript: Request script file Note over Browser,DynamicScript: Network latency DynamicScript-->>Browser: Script content received Browser->>Browser: Parse and execute DynamicScript Note over YourScript: YourScript continues execution YourScript->>YourScript: Attempt to use DynamicScript's functions (may fail) Browser->>YourScript: Dispatch 'load' event (after execution) YourScript->>YourScript: Now safe to use DynamicScript's functions
Sequence of dynamic script loading and potential race condition
Native JavaScript Solutions
Modern browsers provide events that allow you to monitor the state of dynamically loaded scripts. The primary events to consider are load
and error
.
function loadScript(url, callback) {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onload = function() {
console.log(`Script ${url} loaded successfully.`);
if (callback) {
callback(null, script);
}
};
script.onerror = function() {
console.error(`Error loading script ${url}.`);
if (callback) {
callback(new Error(`Failed to load script: ${url}`));
}
};
document.head.appendChild(script);
}
// Usage:
loadScript('https://example.com/my-library.js', function(error, script) {
if (error) {
console.error('Failed to load library:', error);
} else {
console.log('my-library.js is now available!');
// You can now safely use functions/variables from my-library.js
}
});
Loading a script using native JavaScript onload
and onerror
events
onload
event fires when the script has been successfully loaded and executed. The onerror
event fires if there was an issue fetching the script (e.g., 404 error, network issue).jQuery's Approach to Script Loading
jQuery provides a convenient method, $.getScript()
, which simplifies the process of loading and executing JavaScript files asynchronously. It internally handles the creation of the <script>
element and attaches event listeners.
$.getScript('https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js')
.done(function(script, textStatus) {
console.log(`Script loaded: ${textStatus}`); // textStatus will be 'success'
console.log('jQuery UI is now available!');
// You can now safely use jQuery UI functions
$('body').append('<div id="draggable" style="width:100px;height:100px;background:red;"></div>');
$('#draggable').draggable();
})
.fail(function(jqxhr, settings, exception) {
console.error('Error loading script:', exception);
});
Loading a script using jQuery's $.getScript()
method
$.getScript()
method returns a jqXHR
object, which implements the Promise interface. This allows you to chain .done()
for success and .fail()
for error handling, making the code cleaner and more readable.Handling Multiple Scripts and Dependencies
When you need to load multiple scripts, especially if they have dependencies on each other, managing the load order becomes crucial. Promises (native or jQuery's deferred objects) are excellent for this.
Native JavaScript (Promises)
function loadScriptPromise(url) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.type = 'text/javascript'; script.src = url;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Failed to load script: ${url}`));
document.head.appendChild(script);
}); }
// Load scripts sequentially (dependency: script2 needs script1) loadScriptPromise('https://example.com/script1.js') .then(() => loadScriptPromise('https://example.com/script2.js')) .then(() => { console.log('Both script1.js and script2.js are loaded and ready!'); // Safely use functions from both scripts }) .catch(error => { console.error('One or more scripts failed to load:', error); });
// Load scripts in parallel (no dependencies between them) Promise.all([ loadScriptPromise('https://example.com/libA.js'), loadScriptPromise('https://example.com/libB.js') ]) .then(() => { console.log('Both libA.js and libB.js are loaded and ready!'); }) .catch(error => { console.error('One or more parallel scripts failed to load:', error); });
jQuery (Deferred/Promises)
// Load scripts sequentially $.getScript('https://example.com/jquery-plugin1.js') .then(function() { return $.getScript('https://example.com/jquery-plugin2.js'); }) .done(function() { console.log('Both jQuery plugins loaded and ready!'); }) .fail(function(jqxhr, settings, exception) { console.error('One or more jQuery plugins failed to load:', exception); });
// Load scripts in parallel $.when( $.getScript('https://example.com/utility1.js'), $.getScript('https://example.com/utility2.js') ) .done(function() { console.log('Both utility scripts loaded in parallel and ready!'); }) .fail(function(jqxhr, settings, exception) { console.error('One or more parallel utility scripts failed to load:', exception); });
<script>
tags generally bypass some CORS restrictions for execution, errors might not be fully reported to the parent window for security reasons (e.g., onerror
might fire without detailed error information).