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

Next.js接口中Promise.all请求停滞及forEach返回空对象的问题

解决Next.js GitHub API端点的Promise等待问题

问题描述

在Next.js的API端点中调用GitHub API获取仓库及贡献者数据时遇到两个问题:

  • 使用Promise.all批量请求贡献者数据时,API请求停滞无响应,但控制台能看到publicPromises数组已填充数据
  • 改用forEach循环调用getContributors时,返回的数组元素数量正确,但所有对象都是空的

问题原因分析

  1. Promise.all停滞问题:

    • getContributors函数中,当GitHub API返回非200状态码时,仅打印日志但未resolve或reject Promise,导致Promise一直处于pending状态,Promise.all会等待所有Promise完成,因此整个请求停滞
    • 贡献者总数计算逻辑错误:getContributors返回的是单个对象,而非数组,不需要通过repoInfo[0].contributors取值
  2. forEach返回空数组问题:

    • forEach不会返回新数组,且内部异步函数不会被等待,因此publicPromises会是undefined,而非预期的结果数组;需用map生成Promise数组后配合await Promise.all实现异步等待

修复方案

1. 修复getContributors函数

确保所有分支都正确resolve或reject Promise,同时移除不必要的全局数组repoInfo(避免并发请求时的竞态问题):

function getContributors(owner, repo, accessToken, type) {
  return new Promise((resolve, reject) => {
    const options = {
      hostname: 'api.github.com',
      path: `/repos/${owner}/${repo}/contributors`,
      headers: {
        'User-Agent': 'pixls.io',
        'Authorization': `token ${accessToken}`
      }
    };

    const req = https.request(options, res => {
      let data = '';
      res.on('data', chunk => {
        data += chunk;
      });
      res.on('end', () => {
        if (res.statusCode && res.statusCode !== 200) {
          console.log('res.statusCode', res.statusCode);
          console.log("Error...contributors....");
          // 非200状态码时reject终止请求,或resolve默认值(根据需求选择)
          reject(new Error(`GitHub API returned status ${res.statusCode}`));
          // 若需忽略错误继续执行,可替换为:
          // resolve({ name: repo, privacy: type, contributors: 0 });
        } else {
          try {
            const contributors = JSON.parse(data);
            console.log('contributors', contributors.length);
            
            resolve({
              name: repo,
              privacy: type,
              contributors: contributors.length
            });
          } catch (error) {
            console.log("Error...skipping 2....");
            reject(error);
          }
        }
      });
    });

    req.on('error', error => {
      console.error(`Error making GitHub API request: ${error}`);
      reject(error);
    });

    req.end();
  });
}

2. 修复API端点逻辑

修正Promise.all的使用和贡献者总数的计算,确保正确等待所有异步请求完成:

try {
  const { public: publicRepositories, private: privateRepositories, allRepos: repositories } = await getRepositories(accessToken);

  // 生成公共仓库的贡献者Promise数组,并传入type参数
  const publicPromises = await Promise.all(
    publicRepositories.map(repo => 
      getContributors(repo.owner.login, repo.name, accessToken, 'public')
    )
  );
  
  console.log('publicPromise: ', publicPromises);
  
  // 生成私有仓库的贡献者Promise数组,并传入type参数
  const privatePromises = await Promise.all(
    privateRepositories.map(repo => 
      getContributors(repo.owner.login, repo.name, accessToken, 'private')
    )
  );

  // 修正总数计算:直接访问对象的contributors属性
  const totalPublicContributions = publicPromises.reduce((sum, repoInfo) => sum + repoInfo.contributors, 0);
  const totalPrivateContributions = privatePromises.reduce((sum, repoInfo) => sum + repoInfo.contributors, 0);

  const totalContributions = totalPublicContributions + totalPrivateContributions;
  const accountName = publicRepositories.length > 0 
    ? publicRepositories[0].owner.login 
    : privateRepositories[0].owner.login;

  res.status(200).json({
    accountName,
    privateRepoCount: privateRepositories.length,
    publicRepoCount: publicRepositories.length,
    totalContributions,
    publicPromises,
    privatePromises
  });
} catch (err) {
  console.error(err);
  res.status(500).send('An error occurred while fetching the repositories');
}

额外注意事项

  • 若担心GitHub API请求频率限制,可添加请求间隔(如用setTimeout包装Promise),或改用GitHub GraphQL API减少请求次数
  • 处理错误时,可根据业务需求选择终止所有请求,或忽略异常仓库继续执行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 18:35:17