Raising Exceptions

Programming Journey Blog

Check me out on GitHub

Pausing Loops with Await in JavaScript

20 Nov 2020 | programming

When I was working on creating a simple test for my flashcards app, I ran into a problem. I have an object containing the term and answer pairs. The simplest way to go through the test would be to loop through the keys and displays the answer when user clicks on Answer button. The problem was that the loop does not stop on each iteration for the user to select whether their answer was correct or not. I looked up different methods to solve this problem because I wasn’t aware of how asynchronous functions work. Then I stumbled upon a similar StackOverflow question and somebody suggested in the comment to use async.

How Does Async Work Again?

An async function returns a promise and uses the async keyword in front of it:

async function hello() {
  return Promise.resolve(1);
}

Inside an async function, await can be used to pause execution until the promise is returned. This was the main point I needed for my problem. Since execution is paused, I can add an event listener to waits for user input and resolve the promise afterward.

Pausing the Loop

In my app, I have a function to load the test by looping through the terms:

/**
 * Generate test with shuffled array terms.
 * 
 * @param {Object} termsObj 
 */
const loadTest = async termsObj => {
  let terms = Object.keys(termsObj);

  // Shuffle terms randomly
  terms = shuffle(terms);

  // Number of right and wrong answers
  let right = 0;
  let wrong = 0;

  for (let i = 0; i < terms.length; i++) {
    let question = terms[i]
    let answer = termsObj[question];

    showQuestion(question);
    showAnswer(answer);

    // Wait for user to click answer button
    let score = await userAnswer();
    if (score) right++;
    else wrong++;
  }
  showScore(right, wrong);
  hideControl();
  newTest();
}

The loop stops at the line let score = await userAnswer();. It is waiting for the promise of the function userAnswer() to resolve.

/**
 * Clear answer <div> when either correct or incorrect
 * button is clicked.
 * 
 * Resolve 1 for correct or 0 for incorrect.
 */
const userAnswer = () => {

  function clearAnswer() {
    let answer = document.querySelector('.test-answer');
    answer.innerHTML = '';
  }

  return new Promise((resolve) => {
    clearAnswer();

    let correctBtn = document.querySelector('#correct');
    correctBtn.addEventListener('click', () => {
      resolve(1);
    });

    let incorrectBtn = document.querySelector('#incorrect');
    incorrectBtn.addEventListener('click', () => {
      resolve(0);
    });
  });
}

Inside userAnswer(), the promise only resolves when either the Correct or Incorrect button is clicked. If the user does not provide any input, the execution pauses here. async and await made the process of stopping a loop and wait for input simple.

Back to top