Puppeteer中domcontentloaded事件未触发问题咨询
domcontentloaded event firing? The Problem
I'm having trouble understanding how Puppeteer handles the domcontentloaded event. Here's my code:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); page.on('load',()=> console.log('Loaded!',page.url())); page.on('domcontentloaded',()=>console.log('dom even fired')); await page.goto('https://cnn.com'); await browser.close(); })();
When I run this, I don't see the domcontentloaded event log. According to MDN, this event should fire for every webpage—am I making a syntax error, or misunderstanding how Puppeteer works?
The Answer
First off, your code has no syntax errors—the issue comes down to two easy-to-miss quirks with Puppeteer and web navigation:
1. Page Redirects & Output Buffering
When you hit https://cnn.com, it immediately redirects to https://www.cnn.com. The initial cnn.com request redirects so fast that its domcontentloaded event never gets a chance to fire. The redirected www.cnn.com page does fire domcontentloaded, but in some environments, Node.js's console output can be buffered. Even though await page.goto() waits for the load event (which happens after domcontentloaded), the log might not print before browser.close() runs.
2. More Reliable Event Listening
To fix this, you can adjust your code to ensure you capture the event and wait for its callback to finish before closing the browser. Here are two solid approaches:
Approach 1: Use page.once() and Explicit waitUntil
Using page.once() ensures you only listen for the domcontentloaded event from the final redirected page (not the blank initial page). Adding waitUntil: 'domcontentloaded' to page.goto() makes the Promise resolve as soon as the event fires, and a tiny delay ensures logs have time to print:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); // Listen only once for the target page's domcontentloaded page.once('domcontentloaded', () => console.log('dom event fired')); page.once('load', () => console.log('Loaded!', page.url())); // Wait until domcontentloaded fires before proceeding await page.goto('https://cnn.com', { waitUntil: 'domcontentloaded' }); // Give logs a moment to print before closing await new Promise(resolve => setTimeout(resolve, 100)); await browser.close(); })();
Approach 2: Track Events with Promises
For even more reliability, wrap the event listeners in Promises so you explicitly wait for them to complete before closing the browser. This eliminates any race conditions with log buffering:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); // Create promises to track when each event fires const domLoaded = new Promise(resolve => { page.once('domcontentloaded', () => { console.log('dom event fired'); resolve(); }); }); const pageLoaded = new Promise(resolve => { page.once('load', () => { console.log('Loaded!', page.url()); resolve(); }); }); // Start navigation await page.goto('https://cnn.com'); // Wait for both events to finish processing await Promise.all([domLoaded, pageLoaded]); await browser.close(); })();
Why Your Original Code Failed
In your original code, the domcontentloaded event did fire (for the www.cnn.com page), but Node.js's output buffer might have swallowed the log before the browser closed. By explicitly waiting for the event callbacks to complete, you ensure the log gets printed.
内容的提问来源于stack exchange,提问作者skyblue

