When you mention...
I discovered an alternative method to tackle this issue by monitoring DOM changes, but it significantly slowed down the loading time due to the complexity of the DOM structure. I realized that listening for AJAX requests and re-running my code upon their completion would be a more efficient approach.
...were you utilizing Mutation Events or Mutation Observers? I recall that Observers were designed to address such issues. Personally, I hadn't worked with Observers before and opted for Mutation Summary. It seemed capable of achieving the desired outcome, although it only began observing once the document was ready/idle (uncertain which). You might consider scanning on document ready and then triggering the observer.
Below is an outline of how my test code appeared (in a content script)...
handleChanges = function(summaries) {
// Additional elements may need to be ignored
var ignore = {
SCRIPT: true,
NOSCRIPT: true,
CDATA: true,
'#comment': true
}
summaries.forEach(function(summary) {
summary.added.forEach(function(node) {
if (!ignore[node.nodeName] || (node.parentNode && !ignore[node.parentNode.nodeName]) && node.nodeValue.trim()) {
node.nodeValue='PAEz woz ere - '+node.nodeValue;
}
})
})
}
var observer = new MutationSummary({
callback: handleChanges,
// mandatory
rootNode: document,
// optional, defaults to window.document
observeOwnChanges: false,
// optional, defaults to false
queries: [{
characterData: true
}]
});
An additional approach to detecting a XMLHttpRequest involves intercepting it, where the process can be as follows (in a content script at document start).....
function injectScript(source) {
var elem = document.createElement("script"); //Create a new script element
elem.type = "text/javascript"; //It's javascript
elem.innerHTML = source; //Assign the source
document.documentElement.appendChild(elem); //Inject it into the DOM
}
injectScript("("+(function() {
function bindResponse(request, response) {
request.__defineGetter__("responseText", function() {
console.warn('Something attempted to retrieve the responseText');
console.debug(response);
return response;
})
}
function processResponse(request, caller, method, path) {
bindResponse(request, request.responseText);
}
var proxied = window.XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function(method, path, async) {
var caller = arguments.callee.caller;
this.addEventListener('readystatechange', function() {
if (this.readyState === 4)
processResponse(this, caller, method, path);
}, true);
return proxied.apply(this, [].slice.call(arguments));
};
}).toString()+")()");
...learned from the incredibly useful Supper Happy Fun Blog.
However, as you are likely aware, this might not suffice for websites driven by AJAX. It usually necessitates crafting something tailored for the site, or perhaps the Mutation Observer could meet your requirements.