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

Node.js page.goto并发数超预期问题排查及正确实现咨询

问题排查与修复方案

问题根源

你的代码出现并发数超限的核心原因是竞态条件:
当多个请求同时进入page.goto函数时,它们会同时执行if(this.pool.requestingPages > 30)的判断。假设此时requestingPages的值是30,所有这些请求都会判定条件不成立,直接跳过等待逻辑,紧接着执行requestingPages++,导致请求数瞬间突破30的限制,甚至达到35。

除此之外,代码还有两个次要问题:

  • 等待队列使用pop()唤醒请求,会导致后进先出的处理顺序,不符合常规的请求排队逻辑。
  • 成功和失败分支重复了相同的清理代码,冗余且容易出错。

修复后的并发控制代码

// 先保存原始的page.goto方法
const originalPageGoto = page.goto;

page.goto = async function(url, options) {
    // 循环等待,直到有可用的并发槽位
    while (this.pool.requestingPages >= 30) {
        await new Promise(resolve => this.pool.waitList1.push(resolve));
    }

    // 占用一个并发槽位
    this.pool.requestingPages++;
    let result;

    try {
        // 执行原始的goto逻辑
        result = await originalPageGoto.call(this, url, options);
    } catch (e) {
        // 包装错误信息,便于排查
        throw new Error(`goto error: ${e.message}`);
    } finally {
        // 释放并发槽位
        this.pool.requestingPages--;
        // 唤醒等待队列中的第一个请求(先进先出)
        if (this.pool.waitList1.length > 0) {
            const resolve = this.pool.waitList1.shift();
            resolve();
        }
    }

    return result;
};

关键优化点

  1. 避免竞态条件:通过while循环检查并发数,确保只有当requestingPages低于30时,才会占用槽位,从根源上防止并发数超限。
  2. 先进先出的队列处理:使用shift()从队列头部取出唤醒函数,保证请求按进入等待队列的顺序被处理。
  3. 统一清理逻辑:用finally块处理请求完成后的槽位释放和队列唤醒,避免代码冗余。
  4. 错误信息增强:在抛出错误时携带原始错误信息,便于后续排查具体问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 20:27:51