1

I have a loop with two await async functions. I would expect that the second function (F2) would fire after completion of the first await function (F1). But the loop continues without even starting F2. F2 fires only after the F1 async function fires.

I have provided tacking functions to follow the flow.

        for (let i=0; i<5; i++){
        const S3result = (async () => {
          try {
            console.log ('starting await promise 1' );
            params.Key =  '012/' + 'bob1' + i.toString(); 
            await promiseS3(s3, params);
            console.log ('complete 1st upload');
            params.Key = '012/' +  'bob2' + i.toString();
            console.log ('starting await promise 2' );
            await promiseS3(s3, params);
            console.log('completed 2nd upload');

          } catch (e) {
            console.log (e)
          }
        })()



      const promiseS3 = (s3object,params)  => {
        return new Promise((resolve, reject) => {
            console.log ('start s3 Object promise function');
            s3object.upload(params, function(s3Err, data) { 
                if (s3Err) reject  ('bad S3 call')
            console.log(`File uploaded successfully at ${data.Location}`)
            resolve (data); 
            });

        })
      }

I expected F1 to fire, await and then have F2 fire after F1 completes.

This is the output:

starting await promise 1 start s3 Object promise function starting await promise 1 start s3 Object promise function starting await promise 1 start s3 Object promise function starting await promise 1 start s3 Object promise function starting await promise 1 start s3 Object promise function after function File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob14 complete 1st upload starting await promise 2 start s3 Object promise function File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob11 complete 1st upload starting await promise 2 start s3 Object promise function File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob10 complete 1st upload starting await promise 2 start s3 Object promise function File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob12 complete 1st upload starting await promise 2 start s3 Object promise function File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob13 complete 1st upload starting await promise 2 start s3 Object promise function File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob22 completed 2nd upload File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob21 completed 2nd upload File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob23 completed 2nd upload File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob24 completed 2nd upload File uploaded successfully at https://filesafe-beta.s3.us-west-1.wasabisys.com/012/bob20 completed 2nd upload

2
  • Having new lines in the log messages would be very helpful - Commented Aug 13, 2019 at 21:36
  • Some observations after parsing the output stream; notice that your calls aren't being completed in any certain order. ie, The calls complete in the following order (taking the final digits from the file name) 14, 11, 10, 12, 13, 22, 21, 23, 24, 20. I think what you expect is 10, 20, 11, 21, etc.. Is the issue perhaps that all this for loop is doing is assigning new function variables which are immediately being executed? Commented Aug 13, 2019 at 21:44

2 Answers 2

2

You have to put the async above the for loop, not inside the for loop. Remember as soon as an async function hits an await, it returns a promise immediately. So, the way you have it structured, you aren't pausing the for loop at all. You're just creating an async function and executing it over and over in each iteration of the loop and nothing is paying any attention to the promise that the async function returns.

So, you can do it like this:

const S3result = (async () => {
   for (let i=0; i<5; i++){
      try {
        console.log ('starting await promise 1' );
        params.Key =  '012/' + 'bob1' + i.toString(); 
        await promiseS3(s3, params);
        console.log ('complete 1st upload');
        params.Key = '012/' +  'bob2' + i.toString();
        console.log ('starting await promise 2' );
        await promiseS3(s3, params);
        console.log('completed 2nd upload');

      } catch (e) {
        console.log (e)
      }
    }
 })()

Also, S3result will be a promise that will be resolved when the for loop and all the await statements inside it are all done.


Or, like this where you actually await the result of the async function in proper view of the for loop so it will actually pause the for loop (this for loop would itself have to be in an async function in order to use await so there's probably no reason to use the IIFE here. Letting the for loop manage the await statements directly as in first option is probably simpler:

async function someFunction() {
    for (let i=0; i<5; i++){
        await (async () => {
          try {
            console.log ('starting await promise 1' );
            params.Key =  '012/' + 'bob1' + i.toString(); 
            await promiseS3(s3, params);
            console.log ('complete 1st upload');
            params.Key = '012/' +  'bob2' + i.toString();
            console.log ('starting await promise 2' );
            await promiseS3(s3, params);
            console.log('completed 2nd upload');

          } catch (e) {
            console.log (e)
          }
        })();
     }
}
Sign up to request clarification or add additional context in comments.

Comments

1

The issue is that all this for-loop is doing is creating an async function and immediately executing it. So think of it as simultaneously spinning up 5 different instances of the function inside the for-loop.

This is why you get results returned in no particular order. Taking the final digits of the file names, the functions are completing: 14, 11, 10, 12, 13, 22, 21, 23, 24, 20, whereas what I think you expect is 10, 20, 11, 21, ... 14, 24.

To fix this, get rid of the following lines:

const S3result = (async () => {

and

})()

3 Comments

Just to clarify the difference between this answer and jfriend's (posted at the same time), it's just a matter of whether or not this for loop is part of a larger function (my answer), or you want to run it stand-alone (jfriend's answer). The rationale is identical.
thank you - chill94 and jfriend00! Excellent answers - it all works now - much appreciated
@RobertMarlan - Could you mark jfriend's as the accepted answer for future readers (or do the same for mine... but it looks like his is more verbose and descriptive)?

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.