0

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("Correct\n");
        } 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 2

0

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) => {
    //...
});
Sign up to request clarification or add additional context in comments.

Comments

0

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 });
            }
        });
    });
}

Comments

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.