0

I have a async function let say sendEmail which sends emails to users. My sample code is as follows:

const sampleFunc = (users) => {

    for (const user of users) {
        // process user obj and get 'to', 'from', 'body'
        sendEmail(to, from, body) // this is an async function
    }

    return // return only when all the emails are sent.
}

What I want is to return ONLY when all the emails are sent. I can easily do it by adding await before sendEmail function, but then I loose the asynchronous behaviour where I cannot process then next user object unless the email is sent for current user.

Is there a way where I can add sendEmail to something like Promise.all() array dynamically while those already added instances of sendEmail are being processed as I m adding.

For example, if there are 10 users in the users array and currently I'm processing the 5th user, then the sendEmail function is already working for the first 5 users and I'm adding users dynamically. Then just before return, I will wait until all the emails are sent for 10 users, and then return.

Baqir Khan
  • 694
  • 10
  • 25
  • sendEmail returns Promise? – Prime Nov 18 '20 at 04:20
  • Assuming sendEmail returns a Promise, just collect them all into an array and then use Promise.all – codemonkey Nov 18 '20 at 04:27
  • Right now, it returns nothing. But if needed I can make it return a promise. Right now, I am resolving the promises it returns within itself only. – Baqir Khan Nov 18 '20 at 04:29
  • @codemonkey But with this approach, first promise will start execution only after all the users are processed. I want the execution to start before. For me, both sendEmail and processing of users are time consuming tasks. – Baqir Khan Nov 18 '20 at 04:30

1 Answers1

1

When sendEmail returns Promise, you can use Promise.all

const sampleFunc = async (users) => {
    const promises = []
    for (const user of users) {
        // process user obj and get 'to', 'from', 'body'
        promises.push(sendEmail(to, from, body))
    }
    const result = await Promise.all(promises)


    return // return only when all the emails are sent.
}
Prime
  • 2,809
  • 1
  • 7
  • 23
  • But with this approach, first promise will start execution only after all the users are processed. I want the execution to start before. For me, both `sendEmail` and `processing of users` are time consuming tasks. – Baqir Khan Nov 18 '20 at 04:26
  • While processing `Promise.all`, you cannot add more promise dynamically. So you have to create another `Promise.all` process with other group of promises. Maybe you can group promises per specific time range (one group per 1 min). But this is not recommended. – Prime Nov 18 '20 at 04:34
  • @BaqirKhan Prime's code will do exactly what you asked for in your post. Your assumption that the first promise will start executing only after all the users are processed is incorrect. The first call to sendEmail with the first user's info will start executing immediately. – codemonkey Nov 18 '20 at 04:36