I’m using pop state to monitor parameter changes, but one issue I’ve noticed is that when you click backward more than one time, the browser doesn’t interrupt the network requests from the first back, so even though you’ve navigated to a different parameter the data is being pulled from the first backward action’s parameter.
Has anyone encountered this and created a way to cancel the API actions when state changes?
I’m guessing this would require Patrick to modify the AppConnect framework to keep track of on-going XHR requests, and cancel them onPushState/onPopState.
Note, the above alone doesn’t guarantee the server will cancel the request execution, that’s another issue that’s flaky as well based on my experience (the fix I have is deprecated - it’ll stop working in a future NodeJS release)
Yeah, I figured this is something the Wappler team would need to code. I haven’t tested it, but during my search in the forum, I came across a post that mentions Server Connects cancel the request(s). I wonder if the same logic could be easily added to API actions.
I found a way to get you started, it doesn’t cancel requests, but it can track requests made by the page. Took me a couple of tries with ChatGPT!
<script>
// Create a function to log the request details
function logRequest(method, url, payload) {
console.log(`Request: ${method} ${url}`);
if (payload) {
console.log('Payload:', payload);
}
}
// Wrap the XMLHttpRequest.open method
(function(open) {
XMLHttpRequest.prototype.open = function(method, url) {
logRequest(method, url);
open.apply(this, arguments);
};
})(XMLHttpRequest.prototype.open);
// Wrap the fetch function
const originalFetch = window.fetch;
window.fetch = function(url, options) {
logRequest(options?.method || 'GET', url, options?.body);
return originalFetch.apply(this, arguments);
};
</script>
Upon experimental analysis with the code above, I found Wappler uses XMLHttpRequest for making HTTP requests.
Further asking ChatGPT about the possibility of cancelling on-going requests:
Click here to see (long text)
Yes, it is possible to cancel an ongoing fetch or XHR (XMLHttpRequest) request in JavaScript. However, the approaches for cancelling these requests differ slightly.
For XMLHttpRequest (XHR):
To cancel an ongoing XHR request, you can use the abort() method of the XMLHttpRequest object. Here’s an example of how you can do it:
// Create a new XMLHttpRequest object
var xhr = new XMLHttpRequest();
// Set up the request
xhr.open('GET', 'https://example.com/api/data', true);
// Set up an event listener for when the request is complete
xhr.onload = function() {
if (xhr.status === 200) {
// Request was successful
console.log('Request completed successfully.');
} else {
// Request failed
console.log('Request failed.');
}
};
// Set up an event listener for if the request is aborted
xhr.onabort = function() {
console.log('Request was aborted.');
};
// Send the request
xhr.send();
// To cancel the request, call the abort() method
// For example, you can cancel the request after a certain time:
setTimeout(function() {
xhr.abort();
}, 5000); // Cancels the request after 5 seconds
For Fetch API:
Cancelling a fetch request is a bit trickier because the Fetch API does not provide a built-in method to cancel requests like XHR’s abort(). However, you can use the AbortController and AbortSignal interfaces to achieve the same result. Here’s how you can do it:
// Create an AbortController instance
var controller = new AbortController();
// Create an options object with signal property set to the controller's signal
var options = { signal: controller.signal };
// Fetch the data with the fetch() function
fetch('https://example.com/api/data', options)
.then(function(response) {
// Handle the response
if (!response.ok) {
console.log('Request failed.');
} else {
console.log('Request completed successfully.');
}
})
.catch(function(error) {
console.log('Fetch error:', error.message);
});
// To cancel the request, call the abort() method on the controller
// For example, you can cancel the request after a certain time:
setTimeout(function() {
controller.abort();
}, 5000); // Cancels the request after 5 seconds
Keep in mind that once a request is canceled, the fetch() promise will be rejected with an AbortError or the onabort event will be triggered for XHR. Handle these cases appropriately in your code to manage canceled requests gracefully.
So, my proposed approach would be to push the XMLHttpRequest object to an array, and then on push state/on pop state cancel all requests that exist in such array (except the last one, which would be the next page’s fragment load)
// Wrap the XMLHttpRequest.open method
(function(open) {
XMLHttpRequest.prototype.open = function(method, url) {
logRequest(method, url);
if(!window.OngoingXhrRequests) window.OngoingXhrRequests = []; // Create array to store XHR requests, if it doesn't exist already
window.OngoingXhrRequests.push(this); // Push the current XHR object to the array
open.apply(this, arguments);
};
})(XMLHttpRequest.prototype.open);
And then you need to run another JS function OnPopState that will iterate that array window.OngoingXhrRequests and call xhr.abort() except for the last element, where xhr is the current object being iterated of such array
Edit: Also don’t forget to pop out (or otherwise delete) the element after calling .abort(), so the array doesn’t continuously grow
Food for thought:
What happens if you .abort() a XHR request that already completed? Should we we also hook the .ondoneprototype so we can remove it from the array?
Lots to think through. I’m going to put this in the backlog for now (maybe we get lucky and @George or @patrick can implement this in like two hours. )
When the component is being destroyed (removed from DOM) it should do a cleanup. This didn’t happen always in the current stable version of App Connect, we are improving this for App Connect 2.
For the current stable version you can test the following code, it adds the beforeDestroy method to the fetch (serverconnect) component, this method should be called when it is destroyed in a correct way.