-1

Hello I need help on my code. I am not really familiar with Promises. I created a function called EmitRandomNumber(). In this function, after 2 full seconds (2000 ms), it generates a random number between 0 to 100. If the random number generated is below 80, I need to call that function again, up to 10 times, until the random number generated is greater than 80.

let attempt = 1;
let rN; 
function EmitRandomNumber() {
    return new Promise((resolve, reject)=> {
        console.log(`Attempt #${attempt}. EmitRandomNumber is called.`);
        setTimeout(()=>{
            let randomNumber = Math.floor(Math.random() * 100) + 1;
            rN = randomNumber;
            console.log("2 seconds have passed.");
            
            if(randomNumber>=80&&attempt<=10){
                console.log(randomNumber,attempt);

                resolve();
            }else if(randomNumber<80&&attempt<=10){
                attempt++;
                console.log(`Random number generated is ${randomNumber}.`);
                console.log("===============================");
                EmitRandomNumber();
            }
        },2000);
    });
  }

let promise = EmitRandomNumber();

promise.then(()=>{
    console.log(`Random number generated is ${rN}!!!!`);
    console.log("===============================");
}).catch(()=>{
    console.log("End");
});

I dont know if I am using the promise properly and sometimes when it is above 80 it doesnt execute whatever code is in the resolve. Can you help me how I can fix my code. Thank you!

delux
  • 45
  • 6
  • So if the number is bad, do you want it to wait 2 more seconds before trying again? Or should the new try be right away (at the 2 second mark)? – Nicholas Tower May 18 '21 at 02:34
  • If the number generated is below 80, after 2 seconds I generate another number until it reaches attempt #10 or a number above 80 – delux May 18 '21 at 02:38
  • 1
    You never call `resolve()` in the else branch. https://stackoverflow.com/questions/49014833/promise-in-settimeout-loop-return-resolve-or-if-else/49015388 https://stackoverflow.com/a/53032742/1048572 – Bergi May 18 '21 at 02:41

3 Answers3

2

So the code is mostly good, you just did not specify when to 'reject' the promise. From what you described you want this to 'reject' (or display console.log('End')) IF the promise does not find a number after 10 attempts. So you only needed to add a condition (if attempt===10) etc.

EDIT: The resolve and reject need to be returned.

let attempt = 1;
let rN; 
function EmitRandomNumber() {
    return new Promise((resolve, reject)=> {
        console.log(`Attempt #${attempt}. EmitRandomNumber is called.`);
        setTimeout(()=>{
            let randomNumber = Math.floor(Math.random() * 100) + 1;
            rN = randomNumber;
            console.log("2 seconds have passed.");
            if(randomNumber>=80&&attempt<=10){
                console.log(randomNumber,attempt);
                return resolve();
            }else if(randomNumber<80&&attempt<=10){
                attempt++;
                console.log(`Random number generated is ${randomNumber}.`);
                console.log("===============================");
                EmitRandomNumber();
//CHECK FOR CONDITION NUMBER OF ATTEMPTS
            } else if(attempt>10){
                 return reject();
            }
        },2000);
    });
  }


let promise = EmitRandomNumber();

promise.then(()=>{
    console.log(`Random number generated is ${rN}!!!!`);
    console.log("===============================");
}).catch(()=>{
    console.log("End");
});
sychordCoder
  • 230
  • 3
  • 14
  • 1
    Thanks for the help! But I ran the code and after the 3rd attempt it generated 97 but it didnt execute the code in resolve. – delux May 18 '21 at 02:49
  • If in the first attempt it generated number above 80 it executes resolve() but on the succeeding attempts when it generates number above 80 then it dont log whatever is in the resolve() but terminates the program – delux May 18 '21 at 02:53
  • the resolve needs to be returned. Making an edit so you can see. My mistake. – sychordCoder May 18 '21 at 02:55
0

It may be easier to read and reason about using async functions and await. E.g.:

const MAX_TRIES = 10;

const sleep = (ms) => {
    return new Promise(resolve => setTimeout(resolve, ms));
}

const getRandomNumber = () => {
    return Math.floor(Math.random() * 100) + 1;
}

const getNumberWaitAndReturn = async () => {
    let rN = getRandomNumber();
    let attempt = 1;

    while (rN < 80 && attempt <= MAX_TRIES) {
        await sleep(2000);
        rN = getRandomNumber();
        attempt += 1;
    }

    if (attempt > MAX_TRIES) {
        console.log(attempt)
        throw new Error("No luck! It took more than 10 tries!")
    }

    return {
        rN,
        attempt
    }
}

const result = getNumberWaitAndReturn().then(v => {
    console.log(v)
});
Aadmaa
  • 829
  • 5
  • 13
0

You doing pretty good, you just need a little more practice to do it better, I highly recommend you start using closure instead of declaring global variables as you are doing into your code.

Before tell you how you can solve this, I will tell you that are the error, your function will only work as you expect if the first time its executed it generates a random number above of 80, otherwise the function will never be resolved, why ? that's because everytime you are calling the EmitRandomNumber() into the function itself you are creating a new Promise reference so the first one that you created is never handled because you create a new reference promise, so the new reference, it's no handle because your are calling inside the function itself and nobody is doing .then(...).

So how to solve this ? First at all you need to create a closure to create this.

const emitRandomNumber = () => {
  const MAX_ATTEMPTS = 10;
  const MS_START_TIME = 2000;
  const MINIMUM_NUMBER = 80;
  const MAXIMUM_NUMBER = 100;
  let attempts = 0;
  const randomNumber = (max) => Math.floor(Math.random() * max);
  return new Promise((resolve, reject) => {
    const startRandomNumber = () => {
      attempts++;
      const number = randomNumber(MAXIMUM_NUMBER);
      if (number < MINIMUM_NUMBER && attempts <= MAX_ATTEMPTS) {
        return setTimeout(startRandomNumber, MS_START_TIME);
      }
      if (number < MINIMUM_NUMBER && attempts > MAX_ATTEMPTS) {
        return reject();
      }
      resolve(number);
    };
    setTimeout(startRandomNumber, MS_START_TIME);
  });
}

As you can see we are using closure to create function inside function body, so the only function that we call again it's the startRandomNumber function, so this won't generate new promise instances, instead we are keeping the same promise reference and we just execute the random number function until we reach the attempts.

Juorder Gonzalez
  • 1,642
  • 1
  • 8
  • 10