My web app uses esri-leaflet package, it loads geojson via xhr rather than fetch from ArcGIS server. I am trying to use the following code to intercept xhr requests, however, it doesn't work, and the browser doesn't render the cache data, I am not sure what's going on...
The code is running fine, save data to browser's cache storage, and then retrieve data successfully, but no matter how I configurate the xhr response, it seems browser never treat the fake xhr call success, and don't feed back the cached data.
const cache = await caches.open('my-cache');
(function() {
var origOpen = XMLHttpRequest.prototype.open;
var origSend = XMLHttpRequest.prototype.send;
var targeturl, rs;
XMLHttpRequest.prototype.send = async function() {
var self = this;
// Check for cached response before sending the request
const cachedResponse = await caches.match(targeturl, {
//ignoreSearch: true, //true will ignore querystring
ignoreMethod: true,
ignoreVary: true
});
if (cachedResponse) {
// Use cached response
rs = await cachedResponse.json();
Object.defineProperty(self, 'status', {
writable: true,
configurable: true
});
Object.defineProperty(self, 'readyState', {
writable: true,
configurable: true
});
Object.defineProperty(self, 'responseText', {
writable: true,
configurable: true
});
Object.defineProperty(self, 'responseURL', {
writable: true,
configurable: true
});
Object.defineProperty(self, 'response', {
writable: true,
configurable: true
});
self.status = 200; // Set appropriate status code
self.readyState = 4;
self.responseText = JSON.stringify(rs); // Access cached response text
self.response = JSON.stringify(rs);
self.responseURL = targeturl;
self.dispatchEvent(new Event('loadstart'));
self.dispatchEvent(new Event('load'));
self.dispatchEvent(new Event('loadend'));
} else {
// Send the actual XHR request
origSend.apply(self, arguments);
}
};
XMLHttpRequest.prototype.open = function(method, url) {
targeturl = url;
var self = this;
// Corrected event listener logic
self.addEventListener('loadstart', async (e) => {
console.log('request started!');
//try set response again as not working
e.target.status = 200; // Set appropriate status code
e.target.readyState = 4;
e.target.responseText = JSON.stringify(rs); // Access cached response text
console.log(e)
});
self.addEventListener('load', async (e) => {
console.log('request completed!', e, rs);
// Add response to cache if not already cached
const cacheKeys = await cache.keys();
const hit = cacheKeys.find((key) => key.url === url);
if (!hit) {
await cache.add(url); // Cache the actual response
}
});
origOpen.apply(self, arguments);
};
})();
After look at the esri-leaflet source code, I worked out the featureLayer render logic triggered by readystatechange event.
the above code all correct, just need to add
self.dispatchEvent(new Event('readystatechange'));