0

I need some help with javascript loop over fetch api. First I make a call to get projects by user and store then in projetosList. Until here works fine. But when I loop over projetosList to fetch schedules info in listarSchedules function, doesn't works.

Javascript shouts out to me: SyntaxError: await is only valid in async functions, async generators and modules.

I've tried every combination of async-wait except the correct one :(

let urlProjetos = "https://gitlab.com/api/v4/projects?archived=false&private_token=glpat-xx";
let projetosList = [];

function getData(url) {
    return new Promise((resolve, reject)=>{
        fetch(url)
        .then((resp)=>resp.json())
        .then((data)=>{
            return resolve(data);
        })
    });
}

function imprimirProjetos(allUserData) {
    allUserData.forEach((requestPage)=>{
        requestPage.forEach((requestItem)=>{
            let id_nome = requestItem.id + "#" + requestItem.name; 
            projetosList.push(id_nome);
            console.log(id_nome);
        });
    }); 
}

function listarMeusProjetos() {
    let meuId = 123456;
    let urlMeusProjetos = "https://gitlab.com/api/v4/users/" + meuId  + "/projects?private_token=glpat-xx";
    let userRequests = [];

    userRequests.push(getData(urlMeusProjetos));

    Promise.all(userRequests).then((allUserData)=>{
        imprimirProjetos(allUserData);
    });
}

listarMeusProjetos();


// ULTIL HERE WORKS OK


function imprimirSchedule(allUserData) {
    console.log(allUserData);
}

// PROBLEM!!!!
async function listarSchedules() {
    let userRequest = null;
    let allUserData = [];
    let allPromessas = [];

    projetosList.forEach((item)=>{
        let projetoId   = item.split("#")[0];
        let projetoNome = item.split("#")[1];

        console.log("PROJETO ID: " + projetoId + " PROJETO NOME: " + projetoNome);
        let urlSchedule = "https://gitlab.com/api/v4/projects/" + projetoId  + "/pipeline_schedules?private_token=glpat-uSjCXDMEZPh5x6fChMxs";

        console.log("urlSchedule");
        console.log(urlSchedule);

        userRequest = (getData(urlSchedule))
        await userRequest.then((data)=>{
            let str = projetoId + "#" + data.description + "#" + data.owner.username;
            allUserData.push(str)
        })

    });

    imprimirSchedule(allUserData)


}

listarSchedules().then(()=>console.log("DONE"));

Thanks.

walves
  • 2,026
  • 6
  • 28
  • 46
  • `await` is only valid within an async function but your callback to forEach is not defined as async – TheMonarch Jun 08 '23 at 23:37
  • also, async .forEach callback rarely works as you want ... for instance, `imprimirSchedule(allUserData)` will still be called before `allUserData` has any content even if you change the forEach callback to `async` .... – Jaromanda X Jun 08 '23 at 23:45
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) in `getData`! – Bergi Jun 09 '23 at 02:10
  • Btw, you are calling `listarSchedules()` before `listarMeusProjetos()` has filled `projetosList`. Instead of a global variable, you should return a promise for the list. – Bergi Jun 09 '23 at 02:11

2 Answers2

1

You should use an await inside an async function. In your case you can map your project list to url promises, and resolve it with await.

Refactored you problematic function:

// PROBLEM!!!!
async function listarSchedules() {
    const allUserData = await Promise.all(projetosList.map(async item => {

        const [projetoId, projetoNome] = item.split("#");

        console.log("PROJETO ID: " + projetoId + " PROJETO NOME: " + projetoNome);
        let urlSchedule = "https://gitlab.com/api/v4/projects/" + projetoId  + "/pipeline_schedules?private_token=glpat-uSjCXDMEZPh5x6fChMxs";

        console.log("urlSchedule");
        console.log(urlSchedule);

        const {description, owner:{username}} = await getData(urlSchedule);
        return `${projetoId}#${description}#${username}`;

    }));

    imprimirSchedule(allUserData)

}
Alexander Nenashev
  • 8,775
  • 2
  • 6
  • 17
-2

The problem is that the callback function on the projectosList.forEach() was not set to asynchronous. Adding async like this should fix it

async function listarSchedules() {
    let userRequest = null;
    let allUserData = [];
    let allPromessas = [];

    projetosList.forEach(async (item)=>{
        let projetoId   = item.split("#")[0];
        let projetoNome = item.split("#")[1];

        console.log("PROJETO ID: " + projetoId + " PROJETO NOME: " + projetoNome);
        let urlSchedule = "https://gitlab.com/api/v4/projects/" + projetoId  + "/pipeline_schedules?private_token=glpat-uSjCXDMEZPh5x6fChMxs";

        console.log("urlSchedule");
        console.log(urlSchedule);

        userRequest = (getData(urlSchedule))
        await userRequest.then((data)=>{
            let str = projetoId + "#" + data.description + "#" + data.owner.username;
            allUserData.push(str)
        })

    });

    imprimirSchedule(allUserData)
}
seal_szzz
  • 22
  • 2
  • this won't help, since `allUserData` will still be empty at `imprimirSchedule(allUserData)` - for obvious reasons – Jaromanda X Jun 08 '23 at 23:40