2

I currently have a for loop like this:

async myFunc() {
    for (l of myList) {
        let res1 = await func1(l)
        if (res1 == undefined) continue

        let res2 = await func2(res1)
        if (res2 == undefined) continue

        if (res2 > 5) {
            ... and so on
        }
    }
}

The thing is that func1, func2 are network calls which return promises, and I don't want them to block my for loop while waiting for them. So I don't mind working in parallel with myList[0] and myList[1], nor do I care about the order in which the items of the list are processed.

How can I achieve this?

3
  • Instead of having them return a promise you could let em resolve/reject that promise and then just call them in the loop. If you don't want to process the responses. Commented Mar 30, 2021 at 9:33
  • It would be great to have some more code, to see if everything is setup right. Usually you'll do something with .then() after waiting for a Promise, to be sure it runs in order. You could then call another function with your second call in like so .then((result) => { callAnotherFunction(result); }) Commented Mar 30, 2021 at 9:33
  • 1
    @Frizzant - In an async function, you use await (as the OP did above), not .then (95% of the time). Commented Mar 30, 2021 at 10:04

1 Answer 1

5

I'd do it by writing a function that handles the one value that you're handling sequentially:

async function doOne(l) {
    let res1 = await func1(l);
    if (res1 == undefined) {
        return /*appropriate value*/;
    }

    let res2 = await func2(res1);
    if (res2 == undefined) {
        return /*appropriate value*/;
    }

    if (res2 > 5) {
        // ... and so on
    }
}

Then I'd use Promise.all with map to start all of those and let them run in parallel, getting the results as an array (if you need the results):

function myFunc() {
    return Promise.all(myList.map(doOne)); // Assumes `doOne` is written expecting to be called via `map` (e.g., won't try to use the other arguments `map` gives it)
    // return Promise.all(myList.map(l => doOne(l))); // If we shouldn't make that assumption
}

If myList is (or may be) a non-array iterable, use Array.from to get an array to use map on:

function myFunc() {
    return Promise.all(Array.from(myList.map(doOne)));
}

(Or use a for-of loop pushing to an array.)

If you don't want a failure to handle one entry in the list to prevent seeing the results from handling others in the list, use Promise.allSettled rather than Promise.all. (Note that they'll all be started either way, the only difference is whether you see the successful results when at least one of them fails.)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.