0
function foo() {
    let url = `https://foobar.com`
    fetch(url, {
        method: 'POST', 
        headers: headers
    }).then(response => {
        return response.json();
    }).then(data => {
        return data['jobs'];
    }).then(jobs => {
        let successful = [];
        jobs.forEach(job => {
            let jobUrl = job['url'];
            fetch(jobUrl, {
                headers: headers
            }).then(response => {
                return response.json();
            }).then(data => {
                let job_status = data['status'];
                let job_timeStamp = data['timestamp'];
                if (job_status === 'SUCCESS') {
                    console.log(job_status, job_timeStamp);
                    successful.push({jobUrl:jobUrl, timeStamp:job_timeStamp});
                }
            })
        });
        console.log(successful);
    })
}

foo()

When I am running the above code, successful array is not getting populated. How can I populate the successful array? I should be able to sort that array later based on timestamp.

poly_glot
  • 21
  • 5
  • 3
    You are using async code inside the forEach. So the array will be populated AFTER the console log. – Sergio Tx Aug 22 '22 at 10:32
  • 1
    @SergioTx - and potentially in random order :p – Jaromanda X Aug 22 '22 at 10:33
  • 1
    Have you looked into using `async await`, this will avoid thenable hell, and make your code much easier to read. Your `forEach` could also then benefit from `for of` instead.. – Keith Aug 22 '22 at 10:37
  • @Keith - `for...of` is good assuming you want to do the `fetch(jobUrl` in series, rather than parallel – Jaromanda X Aug 22 '22 at 10:40
  • 1
    Does this answer your question? [How to return value from an asynchronous callback function?](https://stackoverflow.com/questions/6847697/how-to-return-value-from-an-asynchronous-callback-function) or [How to access the value of a promise?](https://stackoverflow.com/questions/29516390/how-to-access-the-value-of-a-promise) – evolutionxbox Aug 22 '22 at 11:04

1 Answers1

1

The issue with your code is that fetch is asynchronous, so none of the fetches will have run yet when you console.log(successful)

Here's two alternatives, using async / await since that will simplify the code immensely - I've also used a liberal amount of destructuring sugar

If all the jobUrl fetches can be done in parallel - use this

async function foo() {
    // function to get one jobUrl data
    // called by map later on
    const getJob = async ({url:jobUrl}) => {
        const response = await fetch(jobUrl, {headers});
        const {status, timestamp: timeStamp} = await response.json();
        if (status === 'SUCCESS') {
            return {jobUrl, timeStamp};
        }
    };
    let url = `https://foobar.com`;
    const response = await fetch(url, {method: 'POST', headers});
    const {jobs} = await response.json();
    const unfiltered = await Promise.all(jobs.map(getJob));
    // this "unfiltered" array will have `undefined` items for when status !== SUCCESS
    // so filter them out
    const successful = unfiltered.filter(v => v);
    // here you have successful populated and can use it
}

If the jobUrl fetches have to be done one by one - use this

async function foo() {
    let url = `https://foobar.com`;
    const response = await fetch(url, {method: 'POST', headers});
    const {jobs} = await response.json();
    const successful = [];
    for ({url:jobUrl} of jobs) {
        const response = await fetch(jobUrl, {headers});
        const {status, timestamp: timeStamp} = await response.json();
        if (status === 'SUCCESS') {
            successful.push({jobUrl, timeStamp});
        }
    };
    // here you have successful populated and can use it
}
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87