UNPKG

hd-utils

Version:

A handy utils for modern JS developers

87 lines (85 loc) 2.86 kB
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; }; }