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

JavaScript递归重试请求时程序提前退出原因排查

问题分析与解决方案

核心问题:Promise逻辑错误导致提前退出

你的requestUntilSucceed函数存在致命逻辑问题:当第一次请求失败进入catch分支时,你调用了递归的requestUntilSucceed,但外层的Promise并没有等待这个递归操作完成,而是直接执行了.then((resp) => resolve(attempt)),把第一次的尝试次数作为结果resolve了。

这就导致Promise.all会认为这些“失败后重试”的请求已经成功完成,当所有300个请求对应的Promise都被resolve后,程序就会提前退出,而那些还在重试的请求实际还在后台运行,但已经没人等待它们了。

为什么recursionBypass没用?

这个函数只是简单地直接调用传入的函数,没有做任何异步调度,递归依然是同步执行的——当重试次数足够多时,依然会触发栈溢出,但这不是你这次程序提前退出的原因,核心还是Promise的错误处理。

修复方案

1. 修正requestUntilSucceed的Promise链

不要手动包裹新的Promise,利用Promise链式调用的特性,让失败后的递归请求成为Promise链的一部分,确保只有当最终请求成功时,整个Promise才会resolve:

function sendRequest(url, body, isGood) {
  return fetch(url, body)
    .then(resp => {
      if (isGood(resp)) {
        return resp;
      } else {
        throw resp.status;
      }
    });
}

function requestUntilSucceed(url, body, isGood, name, attempt = 1) {
  return sendRequest(url, body, isGood)
    .then(() => attempt) // 请求成功,返回尝试次数
    .catch(() => {
      // 失败后递归调用,返回新的Promise,让整个链继续等待
      return requestUntilSucceed(url, body, isGood, name, attempt + 1);
    });
}

2. 避免递归栈溢出

如果服务器冷却时间长,重试次数会非常多,同步递归很快会触发栈溢出。可以通过异步调度(比如setTimeout)把下一次重试放到新的事件循环中,同时也能避免短时间内发送大量请求:

function requestUntilSucceed(url, body, isGood, name, attempt = 1) {
  return sendRequest(url, body, isGood)
    .then(() => attempt)
    .catch(() => {
      // 加1秒延迟后重试,可根据实际情况调整
      return new Promise(resolve => setTimeout(resolve, 1000))
        .then(() => requestUntilSucceed(url, body, isGood, name, attempt + 1));
    });
}

3. 修正测试代码的语法错误

你的测试代码中await function()写法错误,需要改成异步立即执行函数,同时不需要额外包裹一层Promise:

(async function() {
  let promises = []; 
  for(let i=0; i<300; i++) {
    promises.push(
      createRequest(requestArg, i)
        .then((attempt) => {
          console.log("Request: ", i, "succeeded on attempt: " + attempt);
          return attempt;
        })
    );
  };
  await Promise.all(promises);
})();

总结

程序提前退出的根本原因是requestUntilSucceed错误地提前resolve了Promise,和所谓的“未知JavaScript限制”无关。修正Promise链式逻辑后,Promise.all会正确等待所有请求最终成功后才结束程序,加上异步调度也能避免递归栈溢出的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:55:17