Using jQuery to Observe Resource Loading Events

What Resource Loading Events Actually Are

When a browser loads a page, it fetches tons of stuff. Scripts, stylesheets, images, fonts, iframes — all of these are resources. Resource loading events let you tap into the lifecycle of these fetches. You can detect when something starts loading, finishes, fails, or times out.

jQuery doesn't have native resource observers like the PerformanceObserver API. But you can still use jQuery to observe and react to resource loading events with a bit of DOM manipulation and event handling.

Why You'd Want to Do This

Common reasons:

jQuery Doesn't Watch Resources Directly

Here's the bitter truth: jQuery is primarily a DOM manipulation library. It wasn't built to observe network requests or resource loading. The $.ajax() and $.get() methods let you track your own AJAX requests, but that's different from observing arbitrary resource loading.

For actual resource observation, you'll need to combine jQuery with native browser APIs. This isn't a limitation of jQuery — it's just not what it's designed for.

The Methods That Actually Work

1. Using $.ajax() for Your Own Requests

If you're loading resources through AJAX, jQuery makes this straightforward:

$.ajax({ url: '/api/data.json', success: function(data) { console.log('Resource loaded:', data); }, error: function(xhr, status, error) { console.error('Failed to load resource:', error); }, complete: function(xhr, status) { console.log('Request finished, regardless of success'); } });

This works for any resource you fetch via XHR. But it won't catch things like <script src> tags or <img> elements.

2. Observing DOM Changes with MutationObserver

You can use a MutationObserver with jQuery to watch when new elements (like scripts or images) get added to the DOM:

var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { $.each(mutation.addedNodes, function(i, node) { if (node.nodeType === 1) { // A new element was added if ($(node).is('script')) { console.log('Script tag detected:', node.src); } if ($(node).is('img')) { $(node).on('load error', function() { console.log('Image event:', this.src, event.type); }); } } }); }); });

Start observing like this:

observer.observe(document.body, { childList: true, subtree: true });

3. Tracking Images with jQuery Event Binding

For images already in the DOM, bind load and error events directly:

$('img').on('load', function() { console.log('Image loaded:', this.src); }).on('error', function() { console.error('Image failed:', this.src); });

This catches images that exist when the script runs. For dynamically created images, bind the event before setting the source:

var img = $('<img>').on('load', function() { console.log('Dynamic image loaded'); }).on('error', function() { console.error('Dynamic image failed'); }).attr('src', '/path/to/image.jpg');

4. Script Loading with $.getScript()

jQuery's $.getScript() loads scripts and executes them. It returns a promise you can chain:

$.getScript('/path/to/script.js') .done(function() { console.log('Script loaded and executed'); }) .fail(function(jqxhr, settings, exception) { console.error('Script failed:', exception); });

Comparison of Methods

Method Use Case Tracks Load Tracks Error Works for Dynamic Content
$.ajax() XHR/AJAX requests Yes Yes Yes
$.getScript() Loading JS files Yes Yes Yes
MutationObserver DOM changes No (just detects addition) No Yes
.on('load/error') Images, iframes Yes Yes Manual binding needed
Native PerformanceObserver All resources Yes Limited Yes

Using PerformanceObserver (The Native Way)

If you need comprehensive resource tracking, use the native PerformanceObserver API. jQuery can coexist with this:

var resourceObserver = new PerformanceObserver(function(list) { list.getEntries().forEach(function(entry) { console.log('Resource:', entry.name); console.log('Type:', entry.initiatorType); console.log('Duration:', entry.duration + 'ms'); }); });

Start observing:

resourceObserver.observe({ entryTypes: ['resource'] });

This catches everything — scripts, stylesheets, images, XHR, fetch, beacons. jQuery is irrelevant here, but you can still use jQuery for DOM manipulation while this runs in the background.

Getting Started: Practical Example

Here's a complete example that tracks resource loading for a specific container:

<div id="resource-tracker"> <img src="/image1.jpg" data-resource="hero-image"> <img src="/image2.jpg" data-resource="thumbnail"> <script src="/analytics.js" data-resource="analytics"></script> </div>

$(function() { // Track images $('#resource-tracker img').each(function() { var $img = $(this); var resourceName = $img.data('resource'); $img.on('load', function() { console.log(resourceName + ' loaded successfully'); $img.addClass('loaded'); }).on('error', function() { console.error(resourceName + ' failed to load'); $img.addClass('error'); }); }); // Track scripts $('#resource-tracker script').each(function() { var script = this; var resourceName = $(this).data('resource'); // Scripts already executed if they have src // For tracking, use getScript if reloading console.log(resourceName + ' script tag present'); }); });

Common Gotchas

When to Skip jQuery Altogether

If resource observation is your main goal, drop jQuery. The native APIs are faster, smaller, and more capable:

jQuery makes sense when you're already using it for DOM manipulation and need a quick resource tracking solution. But if observation is the primary feature, native APIs win every time.