async/await函数未串行执行求助:并行运行而非顺序执行
问题分析与解决
问题根源
你的代码里scrapeHeaders存在语法错误,导致函数未完整执行就提前终止,使得main里的await scrapeHeaders()没有等待函数完成就直接执行了scrapeData(),最终两个浏览器并行启动:
- 变量重复声明:在
scrapeHeaders的循环里,你先声明了const headers = await page.evaluate(...),之后又用const headers = rawHeaders.filter(...)重复声明同名变量,触发语法错误导致函数执行中断。 - 标识符拼写错误:
const pages = possiblePages > maxPages ? max pages : possiblePages;里的max pages是无效写法,应该是maxPages,这个错误同样会让函数抛出异常后终止。
因为这些错误,scrapeHeaders没执行到await browser.close()就提前退出,main中的await会因函数抛出异常直接跳过,进而启动scrapeData,造成两个浏览器并行运行。
解决方案
1. 修复语法错误
修正scrapeHeaders中的两处错误:
// 修正1:变量名拼写错误 const pages = possiblePages > maxPages ? maxPages : possiblePages; // 修正2:避免变量重复声明 const rawHeaders = await page.evaluate(() => { // browser logic return headers; }); const filteredHeaders = rawHeaders.filter( (header) => header !== undefined ) as Header[]; totalHeaders.push(...filteredHeaders); fs.writeFileSync( "headers.json", JSON.stringify(totalHeaders) ); console.log(`got ${filteredHeaders.length} projects info from page ${i + 1}`);
2. 确保函数完整执行(错误捕获与资源清理)
用try/finally包裹浏览器操作,确保即使中间出错,浏览器也能正常关闭;同时在main中添加错误捕获,避免一个函数出错导致流程混乱。
修正后的scrapeHeaders
export async function scrapeHeaders() { let browser; try { const url = 'url'; browser = await puppeteer.launch({ headless: false, defaultViewport: null, }); const page = await browser.newPage(); await changeUserAgent(page); await page.setCookie({ name: "flmdat", value: "value", domain: "www.something.com", path: "/", }); await page.goto(url, { timeout: 0, waitUntil: "networkidle2" }); const someData = await page.evaluate(() => { // browser logic }); if (someData === 0) { console.log("No data available"); return []; } const possiblePages = Math.ceil(someData / 25); const maxPages = 400; const pages = possiblePages > maxPages ? maxPages : possiblePages; console.log("pages to scrape: ", pages); let totalHeaders: Header[] = []; await waitForTimeout(10000); for (let i = 0; i < pages; i++) { console.log(`going to page ${i + 1}`); if (i !== 0) { const nextUrl = `${url}?&page=${i + 1}`; try { await page.goto(nextUrl, { timeout: 60000, waitUntil: "networkidle2", }); } catch (err) { handleError(err, `error while going to ${nextUrl}`); } } const rawHeaders = await page.evaluate(() => { // browser logic return headers; }); const filteredHeaders = rawHeaders.filter( (header) => header !== undefined ) as Header[]; totalHeaders.push(...filteredHeaders); fs.writeFileSync( "headers.json", JSON.stringify(totalHeaders) ); console.log(`got ${filteredHeaders.length} projects info from page ${i + 1}`); } console.log(`scraped ${totalHeaders.length} headers`); } catch (err) { handleError(err, "error in scrapeHeaders"); throw err; // 抛出错误让main函数感知 } finally { if (browser) { await browser.close(); } } }
修正后的main函数
async function main() { try { console.log("scraping headers ... "); await scrapeHeaders(); console.log("scraping data ... "); await scrapeData(); } catch (err) { console.error("Scraping failed:", err); } }
3. 额外优化(可选)
scrapeData中同样建议用try/finally包裹浏览器操作,避免资源泄漏;- 确认
waitForTimeout是正确实现的异步函数,避免出现不等待或阻塞问题。
这样修改后,scrapeHeaders会完整执行(包括关闭浏览器),main中的await会等待它完成后再启动scrapeData,实现真正的串行执行,无需传递数据,完全通过文件交互即可。
内容的提问来源于stack exchange,提问作者Kashif
相关产品推荐
相关产品推荐

