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