You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

async/await函数未串行执行求助:并行运行而非顺序执行

问题分析与解决

问题根源

你的代码里scrapeHeaders存在语法错误,导致函数未完整执行就提前终止,使得main里的await scrapeHeaders()没有等待函数完成就直接执行了scrapeData(),最终两个浏览器并行启动:

  1. 变量重复声明:在scrapeHeaders的循环里,你先声明了const headers = await page.evaluate(...),之后又用const headers = rawHeaders.filter(...)重复声明同名变量,触发语法错误导致函数执行中断。
  2. 标识符拼写错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 10:40:25