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 functionsSequence 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).