hd-utils
Version:
A handy utils for modern JS developers
87 lines (85 loc) • 2.86 kB
JavaScript
import getWindow from './getWindow';
/**
*
* @description --Browser only -- a function that takes onRequestsIdle to be executed when the network becomes idle, which means no active network requests (like XHR or Fetch API) are ongoing.
* @example
* `// Usage
const cancel = networkHttpRequestMonitor((startedRequests, endedRequests) => {
console.log('Network is now idle.');
}, (startedRequests, endedRequests, activeRequestsCount)=>{
console.log("THIS WILL BE CALLED ON EVERY NETWORK REQUEST", {startedRequests, endedRequests, activeRequestsCount})
});
// to cancel
cancel();`
*/
export default function networkHttpRequestMonitor(onRequestsIdle, onEachRequest, options) {
const window = getWindow();
const { intervalMs = 1000, triggerOnWindowLoad = true, cancelAfterIdle = true, } = options || {};
let activeRequestsCount = 0;
let intervalId;
let startedRequests = [];
let endedRequests = [];
let isMonitoring = true;
// Override XMLHttpRequest
const oldXHR = window.XMLHttpRequest;
function newXHR() {
const realXHR = new oldXHR();
realXHR.addEventListener('loadend', function (e) {
endedRequests.push(e.target);
activeRequestsCount -= 1;
callOnRequest();
});
realXHR.addEventListener('loadstart', function (e) {
startedRequests.push(e.target);
activeRequestsCount += 1;
callOnRequest();
});
return realXHR;
}
window.XMLHttpRequest = newXHR;
const oldFetch = window.fetch;
window.fetch = function () {
activeRequestsCount += 1;
startedRequests.push([
...arguments,
]);
return oldFetch
.apply(this, arguments)
.then(async (res) => {
endedRequests.push(res);
activeRequestsCount -= 1;
callOnRequest();
return res;
})
.catch(() => {
activeRequestsCount -= 1;
callOnRequest();
});
};
function onLoad() {
intervalId = setInterval(() => {
if (!isMonitoring)
return clearInterval(intervalId);
if (activeRequestsCount === 0) {
requestIdleCallback(() => onRequestsIdle?.(startedRequests, endedRequests));
if (cancelAfterIdle) {
clearInterval(intervalId);
window.removeEventListener('load', onLoad);
}
}
}, intervalMs);
}
function callOnRequest() {
isMonitoring &&
onEachRequest?.(startedRequests, endedRequests, activeRequestsCount);
}
if (triggerOnWindowLoad) {
window.addEventListener('load', onLoad);
}
else {
onLoad();
}
return () => {
isMonitoring = false;
};
}