Sara Ree
Sara Ree

Reputation: 3543

Leave a for loop containing async-await promises at once

I know if we have an async-await promise inside a for loop like this it will await for resolving the Proceed function on each of the iterations and after the last one we can see the log below the for loop:

for(let i = 0; i < guidePack.length; i++){ 
    await Proceed(guidePack[i]);
}
console.log('Guide is resolved!'); // we will see this only after all of the Proceeds are resolved

Now, what if we want to leave the for at once? like when a user presses the Enter key?

I came up with this code to do it and it seems to work fine:

let guidePack = ['A', 'B', 'C', 'D'];

let ProceedResolved,
    ProceedRejected;




guide(); // initiate proccess

async function guide() {
      StartCaptureKeyPress();
  for(let i = 0; i < guidePack.length; i++){ 
      await Proceed(guidePack[i]);
  }
  console.log('Guide is resolved!');
}


// this function executes speaker function, at speaker function we will resolve the promise
function Proceed(e) {

  console.log(e); // log A and B and C  
  speaker();

  return new Promise((resolve, reject) => { 
    ProceedResolved = resolve; // resolve the Proceed when ProceedResolved() executes
    ProceedRejected = reject;
  });

}

function speaker() {
  // resolve proceed after 6 seconds
    setTimeout(() => ProceedResolved(), 3000);

}

// Capture 'Enter Key' press
function StartCaptureKeyPress() {
        document.addEventListener('keydown', onKeyDownCapture);
    function onKeyDownCapture (event) {
      if (event.keyCode == 13) {
        console.log('Enter Key Pressed');
        document.removeEventListener('keydown', onKeyDownCapture);
        event.preventDefault();
        if (typeof ProceedRejected === "function") { ProceedRejected(); }
      }
    }
}

As you see the code works fine and rejecting one promise will bring us out of the for loop as expected. but each time we reject the promises we get this error:

Uncaught (in promise) undefined

I think we get this error cause we didn't catch the reject error but I don't know :

Upvotes: 0

Views: 51

Answers (1)

slebetman
slebetman

Reputation: 113974

You fix this error as you suspected: by catching it:

async function guide() {
  try {
      StartCaptureKeyPress();
      for(let i = 0; i < guidePack.length; i++){ 
          await Proceed(guidePack[i]);
      }
  }
  catch(err) {
      // do whatever you want
  }
  console.log('Guide is resolved!');
}

Not catching the error will cause issues with any task resolving within the same event loop because the interpreter will simply stop processing further code on any uncaught error. It may or may not cause issues with future tasks - in my experience it does not. You don't need to do anything extra but you need to catch it.

Personally I'd want to know if any real error happened in my code. You can do that by rejecting with your own message and then test to see if it is an error or just a proceed rejection:

// Capture 'Enter Key' press
function StartCaptureKeyPress() {
        document.addEventListener('keydown', onKeyDownCapture);
    function onKeyDownCapture (event) {
      if (event.keyCode == 13) {
        console.log('Enter Key Pressed');
        document.removeEventListener('keydown', onKeyDownCapture);
        event.preventDefault();
        if (typeof ProceedRejected === "function") {
            ProceedRejected("PROCEED_REJECTION"); // <---- NOTE THIS!
        }
      }
    }
}

Then you check it like this:

async function guide() {
  try {
      StartCaptureKeyPress();
      for(let i = 0; i < guidePack.length; i++){ 
          await Proceed(guidePack[i]);
      }
  }
  catch(err) {
      if (err === "PROCEED_REJECTION") {
        // do nothing
      }
      else {
        console.error(err); // or pop up an error dialog
      }
  }
  console.log('Guide is resolved!');
}

Upvotes: 1

Related Questions