Skip to content

Instantly share code, notes, and snippets.

@psenger
Last active April 12, 2024 05:10
Show Gist options
  • Save psenger/14fb81b0088f4e4ad91d8585dc0ad1f6 to your computer and use it in GitHub Desktop.
Save psenger/14fb81b0088f4e4ad91d8585dc0ad1f6 to your computer and use it in GitHub Desktop.
[Promise Design Patterns Timeout on Asynchronous Operations] #JavaScript #Promise
// ----------
// Cancel function!
// ----------
// NOTE:
// This allows us to externalize the cancel function..
// kind of like a inversion of control
let expensiveApplication = delayMs => new Promise(resolve => setTimeout(resolve, delayMs))
// Long Running Process - LRP with cancel function!
let lrp = (promiseToExecute) => {
let cancel;
let promise = new Promise((resolve, reject) => {
cancel = (cancelCause) => reject(cancelCause)
promiseToExecute.then(resolve).catch(reject)
})
return {
promise: promise,
cancel: cancel
};
};
const fiveSeconds = 5 * 1000
const tenSeconds = 10 * 1000
const twentySeconds = 10 * 1000
const CancelInMs = fiveSeconds
const CancelError = new Error(`Process was canceled, ${CancelInMs} ms`);
const run = async () => {
const p = lrp( expensiveApplication(twentySeconds) )
// call cancel...
setTimeout(() => {
p.cancel(CancelError);
}, CancelInMs);
await p.promise
console.log('this should not have occurred.')
return 'done'
}
run()
.then((...args) => {
console.log(...args)
process.exit(0)
})
.catch((e) => {
console.log('Caught an error', JSON.stringify(e.message, null, 4))
process.exit(1)
})
// ----------
// You can use Promise.race() to implement a timeout for an asynchronous operation.
// ----------
// NOTE:
// The promise API does not provide a way to cancel a Pending Operation.
// However, there is a workaround with `setTimeout` and `clearTimeout`.
// This solution does cause issues, allowing the rouge process to continue.
// Long Running Process - LRP
let lrp = delayMs => new Promise(resolve => setTimeout(resolve, delayMs));
const timeOutIn = (delayMs, reason) => new Promise((_,reject)=> setTimeout(()=>reject(reason),delayMs));
const fiveSeconds = 5*1000
const tenSeconds = 10*1000
const twentySeconds = 10*1000
const run = async () => {
const timeOutInMs = fiveSeconds
const TimeOutError = new Error(`Process timed out, ${timeOutInMs} ms`);
// The returned promise settles with the state of the first promise to settle, or rejects on the first rejection
// This behavior allows us to create a Timeout.
const result = await Promise.race([
lrp(tenSeconds),
timeOutIn(timeOutInMs, TimeOutError)
])
console.log('this should not have occurred.')
return 'done'
}
run()
.then((...args) => {
console.log(...args)
process.exit(0)
})
.catch((e) => {
console.log('Caught an error',JSON.stringify(e.message, null, 4))
process.exit(1)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment