如何配置Puppeteer的waitUntil「networkidle」仅监听XHR(AJAX)请求?
How to Make Puppeteer's "Network Idle" Only Consider XHR Requests
Great question! Unfortunately, Puppeteer's built-in networkidle0 and networkidle2 options don't support filtering by resource type—they monitor all network requests, regardless of whether they're XHR, scripts, stylesheets, etc. But we can build a custom solution to mimic "XHR-only network idle" behavior by manually tracking XHR request activity, which pairs perfectly with your existing request interception code.
Here's a robust implementation:
await page.setRequestInterception(true); page.on("request", (request) => { if (request.resourceType() === "image" || request.resourceType() === "font" || request.resourceType() === "media") { console.log("Request intercepted! ", request.url(), request.resourceType()); request.abort(); } else { request.continue(); } }); // Track active XHR requests and wait for idle state let activeXhrRequests = 0; let idleTimeout; const xhrIdlePromise = new Promise(resolve => { // Increment count when an XHR starts page.on('request', request => { if (request.resourceType() === 'xhr') { activeXhrRequests++; // Reset the idle timer if a new XHR comes in if (idleTimeout) clearTimeout(idleTimeout); } }); // Decrement count when an XHR finishes successfully page.on('requestfinished', request => { if (request.resourceType() === 'xhr') { activeXhrRequests--; checkForIdle(resolve); } }); // Handle failed XHRs to avoid hanging indefinitely page.on('requestfailed', request => { if (request.resourceType() === 'xhr') { activeXhrRequests--; checkForIdle(resolve); } }); // Helper to check if we've reached idle state function checkForIdle(resolve) { if (activeXhrRequests === 0) { // Wait 500ms to confirm no new XHRs are fired (adjust this value as needed) idleTimeout = setTimeout(resolve, 500); } } }); // Navigate to the page, wait for DOM to load first await page.goto(url, { waitUntil: 'domcontentloaded' }); // Wait for XHR requests to finish and enter idle state await xhrIdlePromise;
How this works:
- We maintain a counter for active XHR requests. Every time an XHR starts, we increment the count and reset our idle timer to account for new activity.
- When an XHR finishes (either successfully or fails), we decrement the count.
- Once the count hits 0, we wait a short buffer period (500ms in this example) to ensure no new XHRs are initiated. If nothing new comes in, we resolve the promise—signaling that XHR network idle is reached.
Quick adjustments for your use case:
- Tweak the idle buffer: If your app fires XHRs in quick succession, increase the
500mstimeout. For more predictable apps, you can lower it. - Filter specific XHRs: If you need to ignore polling requests or specific endpoints, add a check for
request.url()in the tracking logic to exclude them from the counter. - Add a fallback timeout: To avoid hanging if an XHR gets stuck, wrap
xhrIdlePromiseinPromise.race()with asetTimeoutthat rejects after a maximum wait time.
内容的提问来源于stack exchange,提问作者Nicholas DiPiazza
相关产品推荐
相关产品推荐

