Timeout in async/await
41,315
Solution 1
You can use Promise.race
to make a timeout:
Promise.race([
doSomethingInSeries(),
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), 11.5e3))
]).catch(function(err) {
// errors in res1, res2, res3 and the timeout will be caught here
})
You cannot use setTimeout
without wrapping it in a promise.
Solution 2
Ok I found this way:
async function _doSomethingInSeries() {
const res1 = await callApi();
const res2 = await persistInDB(res1);
const res3 = await doHeavyComputation(res1);
return 'simle';
}
async function doSomethingInSeries(): Promise<any> {
let timeoutId;
const delay = new Promise(function(resolve, reject){
timeoutId = setTimeout(function(){
reject(new Error('timeout'));
}, 1000);
});
// overall timeout
return Promise.race([delay, _doSomethingInSeries()])
.then( (res) => {
clearTimeout(timeoutId);
return res;
});
}
Anyone errors?
The things that smells a bit to me is that using Promises as asynchronicity strategy will send us to allocate too many object that some other strategy needs but this is off-topic.
Comments
-
nkint over 3 years
I'm with Node.js and TypeScript and I'm using
async/await
. This is my test case:async function doSomethingInSeries() { const res1 = await callApi(); const res2 = await persistInDB(res1); const res3 = await doHeavyComputation(res1); return 'simle'; }
I'd like to set a timeout for the overall function. I.e. if
res1
takes 2 seconds,res2
takes 0.5 seconds,res3
takes 5 seconds I'd like to have a timeout that after 3 seconds let me throw an error.With a normal
setTimeout
call is a problem because the scope is lost:async function doSomethingInSeries() { const timerId = setTimeout(function() { throw new Error('timeout'); }); const res1 = await callApi(); const res2 = await persistInDB(res1); const res3 = await doHeavyComputation(res1); clearTimeout(timerId); return 'simle'; }
And I cannot catch it with normal
Promise.catch
:doSomethingInSeries().catch(function(err) { // errors in res1, res2, res3 will be catched here // but the setTimeout thing is not!! });
Any ideas on how to resolve?
-
Bergi almost 8 yearsAre you using a specific promise library?
-
nkint almost 8 yearsNo, just standard promise.
-
Bergi almost 8 yearsSo 2 + 0.5 + 5 + 3 makes a timeout of 11.5 seconds?
-
-
Bergi almost 8 years@nkint: We don't need to clear it because the rejection is not considered when
doSomethingInSeries()
settles first. We could clear it, but that would be rather complicated (optimallyrace
would have a way to cancel the slower promises, but that's not possible with native promises). -
Bergi almost 8 yearsYou're not clearing the timeout if
_doSomethingInSeries()
fails. You should usetry { return await Promise.race(…); } finally { clearTimeout(timeoutId); }
-
nkint almost 8 yearsMaybe I have problem in testing async stuff but seems to me that even if
race
rejects, doSomethingInSeries keep on going its own stuffs. How to be sure to stop everything insidedoSomethingInSeries
if the timeout rejects? -
Bergi almost 8 years@nkint: You cannot stop a promise - it only represents a result (disclaimer: unless you use a promise implementation that supports cancellation). So if there is anything you need to do about the ongoing stuff, you need to do it manually (in the same way you did it with
clearTimeout
in your answer below). -
nkint almost 8 years
it only represents a result
- vary clear, thanks. It's a little bit messy. Some promise I'mawait
-ing indoSomethingInSeries
is a call torequest
with a retry.. I need some other way to handle it, thank you anyway. -
vitalets over 6 years