Last active
April 12, 2024 05:10
-
-
Save psenger/14fb81b0088f4e4ad91d8585dc0ad1f6 to your computer and use it in GitHub Desktop.
[Promise Design Patterns Timeout on Asynchronous Operations] #JavaScript #Promise
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ---------- | |
// 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) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ---------- | |
// 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