Reputation: 313
I have a function which takes a array of GitHub repository names and then I want to send a request with every repository, to get the data about used languages in this repository and add it to an array. It looks like this:
function getRepositoryLanguages(owner, repos) {
var stats = [];
repos.forEach(async (repoName) => {
try {
repoLang = await axios.get(
`https://api.github.com/repos/${owner}/${repoName}/languages`,
{
headers: {
Authorization: "token ${token}",
},
}
);
stats.push(repoLang.data, repoName);
} catch (error) {
console.log(error);
}
});
return stats;
}
I want to get language statistic for every reposository and then store it in array called stats
.
The thing is that this function return an empty array, when I am doing something like this:
getRepositoryNames(username).then((repos) => {
console.log(getRepositoryLanguages(username, repos));
});
I just get an []
.
Does anyone knows how to write this function properly with keeping in mind that those functions will be used in the app.get(/stats)
route?
Upvotes: 1
Views: 97
Reputation: 2330
.forEach
does not play with async behaviour, it expects a synchronous function (see here).
Instead, ensure that your getRepositoryLanguages
function is async
and use a simpler iterator such as a standard for.. of..
loop.
Code example below.
const doSomethingAsync = (repoName) => {
return new Promise(resolve => setTimeout(resolve(repoName+'Lang'), 100));
}
const getRepositoryLanguages = async (owner, repos) => {
let stats = []
for (const repoName of repos) {
const repoLang = await doSomethingAsync(repoName)
stats.push(repoLang)
}
return stats
}
const init = async () => {
const data = await getRepositoryLanguages('username', ['repo1','repo2'])
console.log('data', data)
}
init()
If you're not worried about rate limiting, and wanted to do something in parallel you could Promise.all
like this:
const doSomethingAsync = (repoName) => {
console.log('doSomethingAsync START', repoName)
return new Promise(resolve => setTimeout(() => {
console.log('doSomethingAsync END', repoName)
resolve(repoName + 'Lang')
}, 1000));
}
const getRepositoryLanguages = async(owner, repos) => {
const stats = await Promise.all(repos.map(async(repoName) => {
return doSomethingAsync(repoName)
}))
return stats
}
const init = async() => {
const data = await getRepositoryLanguages('username', ['repo1', 'repo2'])
console.log('data', data)
}
init()
Upvotes: 2
Reputation: 2283
First info:
ForEach loop doesn't stop the execution of the loop even if it has async/await operation in it -> Convert it to normal For Loop for(let i = 0 ....)
/**
*
* @param owner Owner of repository
* @param repos All his public repos
* @returns Language statistics
*/
async function getRepositoryLanguages(owner, repos) {
/**
* language statistics
*/
let stats = [];
for (let index = 0; index < repos.length; index++) {
const repoName = repos[index];
const response = await axios.get(
`https://api.github.com/repos/${owner}/${repoName}/languages`, {
headers: {
Authorization: "token ${token}",
},
}
)
stats.push({
name: repoName,
languages: response.data
});
};
return stats;
}
getRepositoryNames(username).then(async(repos) => {
console.log(await getRepositoryLanguages(username, repos));
});
Upvotes: 1