0

I know await in loops is highly discouraged. But I'm stuck on a specific case I cannot figure out how to do it efficiently. I want a final output of variable values like this

{
  jobId1: [[..], [..], [..], [..]],
  jobId2: [[..], [..], [..], [..]] // list goes on
}

The below snippet represent my current implementation.

for (let jb of jobList ) {
  const subArray = []
  const rel1 = new Parse.Relation(jb, 'applicants')
  const rel2 = new Parse.Relation(jb, 'shortlisted')
  const rel3 = new Parse.Relation(jb, 'hired')
  const rel4 = new Parse.Relation(jb, 'rejected')
  subArray.push(rel1.query().containedIn('objectId', uniqUserIds).select('objectId').find())
  subArray.push(rel2.query().containedIn('objectId', uniqUserIds).select('objectId').find())
  subArray.push(rel3.query().containedIn('objectId', uniqUserIds).select('objectId').find())
  subArray.push(rel4.query().containedIn('objectId', uniqUserIds).select('objectId').find())

  values[jb.id] = await Promise.all(subArray)
}

I can push all the promises into one single array and wait for all. but I'd lose out the track which promise value belongs to which job id. Though splitting the whole await array by every 4th index will get me what I want, I'm looking for even better alternatives.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Faysal Ahmed
  • 1,592
  • 13
  • 25
  • `but I'd lose out the track which promise value belongs to which job id` - no you wouldn't ... and ... last two lines? why? the first assignment to values[jb.id] is meaningless as it is overwritten by the second – Jaromanda X Dec 22 '17 at 09:08
  • + Jaromanda X, as far as I know, it's used to initialize in case of undefined. however i'm editing the snippet – Faysal Ahmed Dec 22 '17 at 09:15
  • 1
    "*I know `await` in loops is highly discouraged.*" - no it's not? If you want sequential iteration, it's exactly the way to go. – Bergi Dec 22 '17 at 09:21

3 Answers3

2

If you want to run all your queries in parallel, you indeed wouldn't use await in the loop. You however do not need to put all your promises in the same array and then split at every 4 values - just use an appropriately nested structure!

function query(jb, name) {
  const rel = new Parse.Relation(jb, name);
  return rel.query().containedIn('objectId', uniqUserIds).select('objectId').find();
}
async function getValues(jobList) {
  const promises = jobList.map(jb =>
    Promise.all([
      jb.id,
      query(jb, 'applicants'),
      query(jb, 'shortlisted'),
      query(jb, 'hired'),
      query(jb, 'rejected'),
    ])
  );
  const results = await Promise.all(promises);
  const values = {};
  for (const [id, ...res] of results)
    values[id] = res;
  return values;
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

I think the way you are doing is efficient. You are taking advantage of asynchronous potencial. I don't think it'd be more efficient if you put all promises together into one array and wait for all of them together. In that case I don't see a way to recover the association between the job id and the result of every promise. It's true that you can refactor all repeated lines, but that's about clean code, not about efficiency. This could be a first approach:

var executeQuery = function(list) {
    const subArray = [];
    for(let element of list) {
       const rel = new Parse.Relation(jb, element);
       subArray.push(rel.query().containedIn('objectId', uniqUserIds).select('objectId').find())
    };
    return subArray;
}

for (let jb of jobList ) {
    values[jb.id] = values[jb.id] || {};
    var subArray = executeQuery(['applicants', 'shortlisted', 'hired', 'rejected']);
    values[jb.id] = await Promise.all(subArray);
}
David Vicente
  • 3,091
  • 1
  • 17
  • 27
-1

Maybe you can use the Q-library for your promises here. With this library you can easily combine and chain your promises.

Hope this helps!

Kind regards.