skip to Main Content

So the purpose of the code is to import JSON questions and read them to the user in the terminal. The user gets 5 seconds to answer the question until the next question is displayed. The issue I am running into is that after the timer is triggered, the next question automatically times out even is the user enters an answer. Here is an example of my log:

Definition: A term used to describe a file or directory location on a drive
1. name
2. separator
3. path
4. prompt
 > 
Please answer within 5 seconds
Definition: A term used to describe a file or directory location on a drive
1. name
2. separator
3. path
4. prompt
 > 3
Please answer within 5 seconds
Definition: A term used to describe a file or directory location on a drive
1. name
2. separator
3. path
4. prompt
 > 3
Correct

Complete: Score - 2/2

And here is my function:

async function vocabularyDrillMode() {
    const definitions = loadJsonFile('definitions.json');
    let score = 0;
    const defBegin = definitions.length;

    async function drillTerm(currentDefinition) {
        console.log(`Definition: ${currentDefinition.definition}`);
        currentDefinition.possibleTerms.forEach((term, index) => console.log(`${index + 1}. ${term}`));

        return new Promise((resolve) => {
            const timer = setTimeout(() => {
                resolve({ success: false, term: "timeout" });
            }, 5000);

            rl.question(" > ", (userAnswer) => {
                clearTimeout(timer);

                const selectedAnswer = parseInt(userAnswer, 10) - 1;

                // Check if the user entered 'q'
                if (userAnswer.toLowerCase() === "q") {
                    resolve({ success: false, term: "q" });
                } else if (!isNaN(selectedAnswer) && selectedAnswer >= 0 && selectedAnswer <= 3) {
                    // If user entered a valid numeric answer
                    resolve({ success: selectedAnswer === currentDefinition.correctDefinition, term: selectedAnswer });
                } else {
                    // If user entered an invalid numeric answer or non-numeric input
                    resolve({ success: false, term: userAnswer });
                }
            });
        });
    }

    let quitDrill = false;

    while (definitions.length > 0 && !quitDrill) {
        const randomIndex = Math.floor(Math.random() * definitions.length);
        const currentDefinition = definitions[randomIndex];

        const result = await drillTerm(currentDefinition);

        if (result.success) {
            score++;
            definitions.splice(randomIndex, 1);
            console.log("Correctn");
        } else if (result.term === "q") {
            quitDrill = true;
        } else if (result.term === "timeout") {
            console.log("Please answer within 5 seconds");
        } else if (isNaN(result.term) || result.term > 3 || result.term < 0) {
            console.log("Please enter a number 1-4 or 'q' to quit the program");
        } else {
            console.log("Incorrect.");
        }
    }

    const statusMessage = quitDrill ? `Incomplete: User quit the drill. Score: ${score}/${defBegin}` : `Complete: Score - ${score}/${defBegin}`; console.log(`${statusMessage}`);
}

I have tried pausing and resuming the readline and I have also tried reordering the console.log of the question and terms to inside the promise and neither solved the issue.

2

Answers


  1. You should use an abort signal to cancel the question when timeout, otherwise you will be answering the previous question after timeout.

    const ac = new AbortController();
    const signal = ac.signal;
    const timer = setTimeout(() => {
        ac.abort();
        resolve({ success: false, term: "timeout" });
    }, 5000);
    
    rl.question(" > ",{signal}, (userAnswer) => {
        //...
    });
    
    Login or Signup to reply.
  2. The documentations shows how to timeout a question using the signal option.
    There is no need to use setTimeout.

    async function drillTerm(currentDefinition) {
        console.log(`Definition: ${currentDefinition.definition}`);
        currentDefinition.possibleTerms.forEach((term, index) => console.log(`${index + 1}. ${term}`));
    
        return new Promise((resolve) => {
            const signal = AbortSignal.timeout(5000);
            signal.addEventListener('abort', () => {
                resolve({ success: false, term: "timeout" });
            }, { once: true });
    
            rl.question(" > ", { signal },  (userAnswer) => {
                const selectedAnswer = parseInt(userAnswer, 10) - 1;
    
                // Check if the user entered 'q'
                if (userAnswer.toLowerCase() === "q") {
                    resolve({ success: false, term: "q" });
                } else if (!isNaN(selectedAnswer) && selectedAnswer >= 0 && selectedAnswer <= 3) {
                    // If user entered a valid numeric answer
                    resolve({ success: selectedAnswer === currentDefinition.correctDefinition, term: selectedAnswer });
                } else {
                    // If user entered an invalid numeric answer or non-numeric input
                    resolve({ success: false, term: userAnswer });
                }
            });
        });
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search