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

递归函数中如何触发原始Promise的resolve?Lambda分页API调用异常问题

问题根因

你代码的核心问题是只有最后一页的api_get返回的Promise被resolve了,前面所有分页对应的Promise实例都从未触发resolve,导致最外层的await api_get('users')永远处于等待状态,自然不会执行后续的"Function finished"日志。

你可以这么理解:每调用一次api_get就会创建一个新的Promise实例。当拉取第1页发现还有下一页时,你只是await了第2页的api_get,但是第1页自己的Promise的resolve()方法从来没有被调用过;同理第2页、第N-1页的Promise都没有被resolve,只有最后一页走到了else分支调用了resolve,外层等待的是第1页的Promise,它永远处于pending状态,所以代码卡住。

修复方案

你只需要在递归调用完下一页的api_get之后,把当前页的Promise也resolve掉即可,改动很小:

exports.handler = async (event, context, callback) => {
  let db = await initDB(); // External function
  try {
    await api_get('users')
    console.log("Function finished");
  } catch (err) {
    console.error('执行出错', err)
  } finally {
    db.end()
    callback(null)
  }

  function api_get(type, page = 1, count = 0, results = []) {
    return new Promise(function(resolve, reject) {
      // 不要给Promise构造函数的入参加async,无意义还容易引发上下文错误
      let uri = `https://api.com/v1/${type}`;
      request.get(uri + '?page=' + page, async (error, response, body) => {
        // 新增错误处理,避免请求出错时Promise永久pending
        if (error) return reject(error)
        try {
          const data = JSON.parse(body);
          results.push(data.users)
          const current_count = count + data.meta.count
          if (current_count < data.meta.total) {
              await api_get(type, page + 1, current_count, results);
              // 递归完成后直接resolve当前页的Promise
              resolve()
          }
          else {
              await parseData(type, results)
              resolve()
          }
        } catch (parseErr) {
          reject(parseErr)
        }
      });
    });
  }
  
  function parseData(type, data) {
    return new Promise(function(resolve, reject) {
      switch (type) {
        case 'users':
          let users = [].concat(...data)
          // 注意:原代码中的user_id变量不存在,需根据实际字段改为user.user_id/user.id
          // 注意:直接拼接SQL存在严重SQL注入风险,建议改为参数化查询
          let sql = ''
          for (const user of users) {
            sql = sql + `INSERT INTO users (user_id) VALUES ('${user.user_id}');`
          }
          db.query(sql)
          .then(() => resolve())
          .catch(sqlErr => reject(sqlErr))
        break;
        default:
          resolve()
      }
    });
  }
};

其他优化建议

  • 停止使用已废弃的request库,替换为axios、got等仍在维护的HTTP请求库
  • 所有异步操作统一添加try/catch捕获,避免Lambda无意义超时
  • 数据库写入操作改用参数化查询,完全避免SQL注入风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 17:24:03