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

为何我的Promise会比预期提前resolve?Torn API调用问题排查

问题排查与修复方案

核心问题根源

1. getItemUpdated 函数逻辑错误

你当前的getItemUpdated是async函数返回手动创建的Promise,但executor函数里既没有调用resolve也没有调用reject,导致这个Promise会直接默认resolve为undefined,完全不符合预期。而且async的executor函数本身会导致Promise的异常处理混乱。

2. callTornApi 未捕获网络异常

当axios请求抛出网络错误(比如超时、连接失败)时,代码没有try/catch捕获,会直接终止while循环,导致callTornApi的Promise直接reject,无法完成最多5次重试的逻辑。

3. 入口循环的重试逻辑不可靠

用i--修改for循环计数器的方式,结合await异步逻辑,很容易出现循环次数异常(比如重复处理同一个ID或者跳过ID),而且依赖getItemUpdated的reject才能触发,但当前getItemUpdated根本不会reject。


分步修复代码

1. 修复 getItemUpdated 函数

去掉多余的手动Promise创建,直接利用async函数的特性,正确处理成功和失败的情况:

const getItemUpdated = async (itemId) => {
  const result = await api.market.getLowestListing(itemId);
  // 补充你删除的校验逻辑,判断result是否有效
  if (!result) {
    throw new Error(`获取商品${itemId}数据失败`);
  }
  // 其他业务处理逻辑放在这里
  return result;
};

2. 修复 callTornApi 的异常捕获与重试逻辑

给axios请求加上try/catch,确保网络错误也能触发重试,同时用局部变量隔离重试次数,避免并发请求互相干扰:

async callTornApi(url: string, params?): Promise<object | null> {
  let retries = 0;
  const maxRetries = 5;

  while (retries < maxRetries) {
    try {
      if (this.debug) {
        console.log('Calling Torn API... ', url, params);
      }

      const { data } = await axios.get(url, { params });

      if (data.error) {
        if (this.debug) {
          console.log('Wrapper API Error: ', data.error.error, ' Code: ', data.error.code, ' Retries: ', retries);
        }

        this.error = {
          code: data.error.code,
          message: data.error.error
        };

        if (data.error.code === 2) {
          this.removeKey(params.key);
        }

        await new Promise(resolve => setTimeout(resolve, this.retryTimeout));
        retries++;
      } else {
        this.error = undefined;
        return data;
      }
    } catch (networkError) {
      // 捕获网络错误(超时、断网等)
      if (this.debug) {
        console.log('Network Error: ', networkError.message, ' Retries: ', retries);
      }
      await new Promise(resolve => setTimeout(resolve, this.retryTimeout));
      retries++;
    }
  }

  // 重试5次都失败
  this.error = {
    code: -1,
    message: '达到最大重试次数'
  };
  return null;
}

3. 修复入口循环的重试逻辑

用while循环代替for循环,避免修改计数器导致的异常:

let currentIndex = 0;
const totalItems = itemIds.length;

while (currentIndex < totalItems) {
  const itemId = itemIds[currentIndex];
  try {
    const res = await getItemUpdated(itemId);
    if (res) {
      await informUser(client, itemId);
      currentIndex++; // 成功后才推进索引
    }
  } catch (err) {
    console.log(`商品${itemId}请求失败,等待重试...`);
    await wait(5000);
    // 失败不推进索引,继续重试当前ID
  }
}

4. 完善 getLowestListing 的错误处理

确保当getItems返回null时,上层能感知失败:

async getLowestListing(itemId: number): Promise<LowestListing | null> {
  const bazaarItems = await this.bazaar.getItems(itemId, 1);

  if (this.api.error || !bazaarItems) {
    // 可选择抛出错误或返回null,根据上层逻辑调整
    // throw new Error(`获取最低 listing 失败: ${this.api.error?.message}`);
    return null;
  }
  
  // 补充你删除的业务处理逻辑,比如提取最低价格数据
  return processedResult;
}

关键说明

  • 永远不要在Promise构造函数的executor里用async函数,这会导致异常无法被捕获,Promise状态混乱。
  • 网络请求的重试必须捕获所有异常,包括axios抛出的网络错误,否则会中断重试流程。
  • 循环处理异步任务时,避免修改for循环的计数器,改用while循环控制索引更安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 19:07:15