Home > database >  Make error throw in calling function instead of timeout
Make error throw in calling function instead of timeout

Time:10-20

I have a loop which resets a timeout every time it completes an iteration, but if the loop takes too long I want to throw an error that is caught by an exception handler from the calling function. How can I throw the error in the parent instead of inside the timeout scope?

Where I'm applying this is attempting to access web pages and if not I have a set of instructions to reset the connection, but hopefully this mwe makes enough sense as a standalone example.

const wait = ms => new Promise(r => setTimeout(r, ms));
const getRand5 = () => Math.floor(Math.random() * 5   1);
const wait5 = () => wait(getRand5() * 1e2);

async function something() {
  for (let i = 0; i < 10; i  ) {
    //I want this thrown error to throw an error for function something, not the timeout scope
    const timer = setTimeout(() => { throw new Error("too long!"); }, 3e2);
    await wait5();
    clearTimeout(timer);
  }
}

(async () => {
  let fails = 0;
  do {
    try {
      console.log("attempt number ", fails);
      await something();
      break;
    } catch (e) {
      fails  ;
    }
  } while (fails < 10);
  if (fails >= 10)  {
    console.log("failed too many times");
  } else {
    console.log("Looks like we gottem boys");
  }
})();

CodePudding user response:

You could solve this using Promise.race() with (of course) Promises.

Example:

// Timeout helper function
// Returns a promise which gets resolved after `ms` milliseconds
async function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms, "timed_out");
  });
}

async function something() {
  // Race Timeout and Wait5 promises here
  // If Timeout promise resolves, it will
  // resolve the value "timed_out"
  const result = await Promise.race([
    timeout(3e2),
    wait5(),
  ]);

  // Check resolved value here; if timed out, throw error
  if (result === "timed_out") {
    throw new Error("too long!");
  }
}

CodePudding user response:

From some comments this is how I solved the problem in my specific situation. Instead of trying to throw an error, I changed the function from async to returning a promise, and used the reject function to exit early if needed.

const wait = ms => new Promise(r => setTimeout(r, ms));
const getRand5 = () => Math.floor(Math.random() * 5   1);
const wait5 = () => wait(getRand5() * 1e2);

function something() {
    return new Promise(async (resolve, reject) => {
        for (let i = 0; i < 10; i  ) {
            //I want this thrown error to throw an error for function something, not the timeout scope
            const timer = setTimeout(() => { reject() }, 4e2);
            await wait5();
            clearTimeout(timer);
        }
        resolve();
    });
}

(async () => {
    let fails = 0;
    do {
        try {
            if (fails % 10 == 0)console.log("attempt number ", fails);
            await something();
            break;
        } catch (e) {
            fails  ;
        }
    } while (fails < 100);
    if (fails >= 100) {
        console.log("failed too many times");
    } else {
        console.log("Looks like we gottem boys");
    }
})();

  • Related