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

如何拆分Puppeteer异步方法,分批执行100页面自动化测试任务

分批处理Puppeteer任务,降低CPU负载

这个场景太常见了——一次性拉起100个页面执行异步操作,CPU肯定扛不住。咱们可以通过分批串行处理来解决,每次只启动指定数量的页面(比如你说的20个),等一批全部完成后再启动下一批,这样就能把资源占用控制在合理范围内。

先分析原代码的问题

你原来的代码用Object.keys(requirementsMap).forEach(async (key) => { ... }),然后await Promise.all(promises)——这会一次性把100个页面的创建、操作Promise全部启动,相当于同时打开100个页面,CPU直接拉满是必然的。

解决方案:分批处理

核心思路是:把所有任务分成小批次,用for循环(而不是forEach)控制批次的串行执行,每批内部并行处理20个任务,批与批之间等待完成。

下面是修改后的完整代码,我加了详细注释:

export default {
  async checkAllKeys() {
    const requirementsMap = {
      key_1: [this.method1, this.method2, this.method3],
      key_2: [this.method1, this.method2, this.method3],
      // ... 剩下的98个key
      key_100: [this.method1, this.method2, this.method3],
    };
    const result = {};
    const allKeys = Object.keys(requirementsMap);
    const batchSize = 20; // 每次处理20个页面,可根据机器性能调整

    // 分批循环处理,for循环能保证批次串行执行
    for (let i = 0; i < allKeys.length; i += batchSize) {
      // 截取当前批次的key
      const currentBatchKeys = allKeys.slice(i, i + batchSize);
      console.log(`开始处理第${Math.floor(i/batchSize)+1}批,共${currentBatchKeys.length}个任务`);

      // 处理当前批次的每个任务
      const batchTasks = currentBatchKeys.map(async (key) => {
        let newPage;
        try {
          newPage = await browser.newPage();
          await newPage.goto('http://www.example.com/');
          
          const requirements = requirementsMap[key];
          // 执行当前key的所有异步方法,捕获单个方法的错误
          const keyResults = await Promise.all(
            requirements.map(req => req.call(this, newPage).catch(() => 'error occurred'))
          );
          result[key] = keyResults;
        } catch (globalErr) {
          // 捕获页面创建、跳转等全局错误,避免影响整个批次
          result[key] = ['页面操作全局错误'];
          console.error(`处理key ${key}时发生全局错误:`, globalErr);
        } finally {
          // 无论成功失败,都确保页面关闭,防止内存泄漏
          if (newPage) await newPage.close();
        }
      });

      // 等待当前批次所有任务完成,再进入下一批
      await Promise.all(batchTasks);
      // 可选:每批之间加短暂延迟,给CPU喘息时间
      // await new Promise(resolve => setTimeout(resolve, 500));
    }

    return result;
  },

  async method1(newPage) {
    // 你的异步操作逻辑,比如点击、输入等
  },

  async method2(newPage) {
    // 注意:原代码里method2没传newPage,这里补上(如果需要用到页面的话)
    // 你的异步操作逻辑
  },

  async method3(newPage) {
    // 你的异步操作逻辑
  },
};

关键改进点

  1. 串行批次,并行内部任务:用for循环控制批次,每批完成后再处理下一批;每批内部用Promise.all并行处理20个页面,兼顾效率和资源占用。
  2. 简化Promise逻辑:去掉了原代码中不必要的new Promise(async (resolve, reject))——async函数本身就返回Promise,直接用map生成任务Promise即可。
  3. 完善错误处理:增加try/catch/finally,确保页面无论如何都会关闭,避免内存泄漏;同时捕获单个方法和全局操作的错误,不会因为一个任务失败导致整个批次挂掉。
  4. 可调试性:增加了批次处理日志,方便跟踪进度。

额外优化建议

  • 如果你的机器性能还是有点吃紧,可以把batchSize调小一点(比如15);如果性能足够,也可以调大。
  • 可以在批次之间加短暂延迟(比如代码中注释的500ms),进一步降低CPU峰值。

内容的提问来源于stack exchange,提问作者domlas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:01:13