javascript 无法在循环中等待promise以防止延迟请求

ndh0cuux  于 2023-05-05  发布在  Java
关注(0)|答案(1)|浏览(126)

这段代码是Next.js webapp的API端点,它获取所有的github仓库,仓库的名称和贡献者的数量。但问题是,当我使用Promise.all时,调用不返回任何东西(停止响应),并且在console.log()中,我可以看到填充的数组。否则,如果我没有在forEach或Map循环中使用Promise.all和useupdate数组,我将返回带有Repos数量的数组,但所有对象都为空。

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

  const publicContributions = []
  const privateContributions = []

  const publicPromises = await Promise.all(publicRepositories.map(async repo => await getContributors(repo.owner.login, repo.name, accessToken)))
  
  console.log('publicPromise: ', publicPromises)
  
  const privatePromises = await Promise.all(privateRepositories.map(async repo => await getContributors(repo.owner.login, repo.name, accessToken)))

  const totalPublicContributions = publicPromises.reduce((sum, repoInfo) => sum + repoInfo[0].contributors, 0);
  const totalPrivateContributions = privatePromises.reduce((sum, repoInfo) => sum + repoInfo[0].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
  });
} catch (err) {
  console.error(err);
  res.status(500).send('An error occurred while fetching the repositories');
}

getRepositories返回Privarte/Public repos数组,但是当我用forEach获取getContributors()时,它在数组中返回28个空对象(意味着我们有28个公共repos,但没有任何数据)。

const publicPromises= publicRepositories.forEach(async repo => {
    const contributors = await getContributors(repo.owner.login, repo.name, accessToken);
    console.log('totalPublicContributions:', contributors)
  });

下面是getContributors函数

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...."); 
          } else {
            try {
              const contributors = JSON.parse(data);
              console.log('contributors', contributors.length)
              
              repoInfo.push({
                'name': repo,
                'privacy' : type,
                'contributors': contributors.length
              })
              
              resolve({
                'name': repo,
                'privacy' : type,
                'contributors': contributors.length
              });
            } catch (error) {
              console.log("Error...skipping 2...."); 
            }
          }
        });
      });
  
      req.on('error', error => {
        console.error(`Error making GitHub API request: ${error}`);
        reject(error);
      });
  
      req.end();
    });
  }

如何等待响应,以便我可以在res.json中发送填充的'publicPromises'

relj7zay

relj7zay1#

需要解决的一件事是在getContributors()的所有代码路径中解析或拒绝promise。您有两个代码路径,它们只记录日志,从不实现promise,一个是在测试状态时,另一个是在JSON.parse()抛出时。当Promise.all()中涉及的promise从未解析/拒绝时,那么await Promise.all()将永远不会解析,并且您的代码将“卡住”等待永远不会完成的promise。
你可以像这样修复它:

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...."); 
            // ==== Add next line ===
            reject(new Error(`statusCode was ${res.statusCode}`));
          } else {
            try {
              const contributors = JSON.parse(data);
              console.log('contributors', contributors.length)
              
              repoInfo.push({
                'name': repo,
                'privacy' : type,
                'contributors': contributors.length
              })
              
              resolve({
                'name': repo,
                'privacy' : type,
                'contributors': contributors.length
              });
            } catch (error) {
              console.log("Error...skipping 2...."); 
              // ==== Add next line ===
              reject(error);
            }
          }
        });
      });
  
      req.on('error', error => {
        console.error(`Error making GitHub API request: ${error}`);
        reject(error);
      });
  
      req.end();
    });
  }

如果你想得到所有的响应,即使有些拒绝,那么你可以使用await Promise.allSettled(...)而不是await Promise.all(...),然后迭代结果,看看哪些是成功的,哪些不是。

相关问题