问题
BRIEF
I have a website which gets data from an API. So it makes some post and get requests to a server once the website is opened. Let us assume it makes 5 different xmlHttpRequests as soon as the page loads but we cannot exactly know the time each call takes from start to finish.
FOR EXAMPLE
Call to one endpoint takes 2 seconds to complete and the other one takes 1 second to complete. So that means after 2 seconds both the calls are said to be finished.
TO-DO
I want to execute a function after all the xmlHttpRequests are complete because I am using window.performance.getEntries() to fetch all the requests initiated by the webpage and send it to my server as I am doing a web analytics project in which I need to access the times taken by each network request and convert the data into a chart.
EXTRA-QUESTION OR HINT
Is there any event that can be attached to the window as shown below to listen for all the network calls and execute my piece of code when all are finished.
window.addEventListener("load", function (event) {
//execute some code here
}
In the load event I am not able to capture all the requests by using performance.getEntries() because load fires before the ajax calls are finished.
As shown above I ask. Is there any trick or any event or anything in JavaScript by which we can wait untill all the XMLHTTPREQUESTS are finished and then execute some code.
回答1:
WORKING SOLUTION
We can track browser AJAX calls using the code below :
const ajaxCallStatus = () => {
window.ajaxCalls = 0; // initial ajax calls
window.ajaxEndpoints = []; // keeping track of all ajax call urls (endpoints)
const origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
window.ajaxCalls++;
this.addEventListener('load', (event) => {
if (!window.ajaxEndpoints.includes(event['currentTarget'].responseURL)) {
window.ajaxEndpoints.push(event['currentTarget'].responseURL);
}
window.ajaxCalls--;
switch (window.ajaxCalls) {
case 0: // when ajax calls finish this runs
addData(window.ajaxEndpoints);
break;
}
});
origOpen.apply(this, arguments);
}
}
ADD DATA FUNCTION - Used for sending data to some backend.
function addData(arr, origOpen) {
XMLHttpRequest.prototype.open = origOpen;
axios.post('url', data)
.then((res) => console.log(res))
.catch((err) => console.log(err));
}
回答2:
I would suggest you to wrap your requests in promises and then use Promise.all(...)
like so:
const makeRequest = () => {
return new Promise((resolve, reject) => {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
resolve(xhttp.responseText); // On success, resolve the promise
} else {
reject(); // On failure, reject it
}
};
xhttp.open("GET", "filename", true); // Needs to be set to your needs. This is just an example
xhttp.send();
});
}
// This waits until all promises are resolved
const [result1, result2] = await Promise.all(makeRequest(), makeRequest());
// do stuff here with your results
console.log(result1);
console.log(result2);
PS: Basic Ajax example is from here, but just swap it for yours and create parameters or similar to make the requests you actually need
OR
You could use a library like Axios for Ajax requests, which already returns Promises by default. Check it out here: https://github.com/axios/axios
来源:https://stackoverflow.com/questions/63503441/execute-a-function-when-all-xmlhttprequests-are-complete