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

JS中while循环内async axios请求未等待执行完成问题排查

问题根因
  • 核心错误:while循环是同步执行逻辑,你在循环内部包裹axios请求的立即执行异步函数没有加await阻塞,循环触发异步任务后会直接进入下一轮迭代,完全不会等待请求返回、task状态更新,最终导致循环无等待快速空转、请求乱发。
  • 附带的其他逻辑bug:
    • 代理重复获取:switch逻辑外先调用了一次getNextProxy(),异步函数内部又调用了一次,两次拿到的代理不一致,会导致代理调度混乱。
    • axios传参错误:你把timeout:5000单独作为第三个参数传入,实际上axios所有配置都要放在第二个参数对象里,当前写法超时配置完全不生效。
    • 循环终止逻辑失效:case "new"中判断url == "end"时的break只能跳出switch分支,无法终止外层while循环,会继续往下执行无效请求。
    • 无重试上限:遇到验证码、请求错误就切代理重试的逻辑没有次数限制,代理池耗尽时会触发死循环。
    • 翻页逻辑缺失:case "next"分支没有对pageNumber做自增,会重复请求同一页内容。
修正后代码

把整个爬取逻辑包裹在异步函数中,每轮循环等待当前请求执行完成后再进入下一轮,同时修复上述逻辑问题:

const MAX_RETRY = 10; // 最大代理重试次数,避免死循环
let retryCount = 0;

async function startCrawl() {
  let task = "new";
  let pageNumber = 1;
  let url = "";

  while( (task == "new") || (task == "next") || (task == "proxy")) {
    // 重试次数超限直接终止
    if (retryCount >= MAX_RETRY) {
      console.log("Retry limit reached, crawl stopped");
      return;
    }

    switch(task) {
      case "new":
        pageNumber = 1;
        url = getNextUrl(pageNumber);
        if(url == "end") {
          console.log("Search completed!");
          return; // 直接终止函数,跳出循环
        }
        retryCount = 0; // 新任务重置重试计数
        break;
      case "next":
        pageNumber += 1;
        url = getNextUrl(pageNumber);
        retryCount = 0; // 正常翻页重置重试计数
        break;
      case "proxy":
        retryCount += 1;
        break;
    }

    // 单次只取一次代理,避免重复调度
    const proxy = getNextProxy().toString().split(":");
    console.log("Using proxy:", proxy);
    console.log("Request url:", url);

    try {
      const response = await axios.get(url,{
        headers: {
          'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.66 Safari/537.36"
        },
        proxy: false,
        timeout: 5000, // timeout放到配置对象内部
        httpsAgent: new HttpsProxyAgent.HttpsProxyAgent(`http://${proxy[0]}:${proxy[1]}`)
      });

      const $ = cheerio.load(response.data);
      const captcha = $("#captcha-form");
      if(captcha.length > 0) {
        task = "proxy";
        continue; // 直接进入下一轮循环切代理
      }

      const searchitems = $(".jtfYYd");
      for(let i=0; i < searchitems.length; i++) {
        const element = searchitems[i];
        const link = $(element).find(".yuRUbf").find("a").attr('href');
        const title = $(element).find("h3").text();
        const details = $(element).find(".MUxGbd.wuQ4Ob.WZ8Tjf").find("span");
        const stub = $(element).find(".VwiC3b.yXK7lf.MUxGbd.yDYNvb.lyLwlc.lEBKkf").find("span").text();

        console.log();
        console.log("Title:     " + title);
        console.log("Link:      " + link);
        console.log("Details:   " + details);
        console.log("Stub:      " + stub);
      }

      const botstuff = $("#botstuff");
      console.log("botstuff: " + botstuff.text());

      if(botstuff.text().indexOf("Next") > 1) {
        task = "next";
      } else {
        task = searchitems.length == 0 ? "proxy" : "new";
      }
    } catch (error) {
      // 请求出错切代理重试
      task = "proxy";
    }
  }
}

// 启动爬虫
startCrawl();
补充说明
  • 修正后统一用async/await语法代替了原来混用的.then()写法,逻辑更清晰,每轮循环会阻塞等待当前axios请求返回、task状态更新完成后才会进入下一轮,不会出现空转问题。
  • 加了最大重试次数限制,避免代理失效时无限死循环占满资源。
  • 去掉了重复的代理获取、重复变量定义逻辑,每轮请求只调度一个代理,不会出现代理不匹配的问题。
  • 修正了axios配置参数的位置,超时规则可以正常生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:18:31