Last active
June 30, 2023 14:08
-
-
Save DavidWells/56089265ab613a1f29eabca9fc68a3c6 to your computer and use it in GitHub Desktop.
Nicer business logic with async wait promises that won't swallow native JS errors. Update to https://gist.github.com/DavidWells/54f9dd1af4a489e5f1358f33ce59e8ad where we handle native JS errors instead of potentially missing them. Now a package here https://www.npmjs.com/package/safe-await
This file contains hidden or 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
/* Native Error types https://mzl.la/2Veh3TR */ | |
const nativeExceptions = [ | |
EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError | |
].filter((except) => typeof except === 'function') | |
/* Throw native errors. ref: https://bit.ly/2VsoCGE */ | |
function throwNative(error) { | |
for (const Exception of nativeExceptions) { | |
if (error instanceof Exception) throw error | |
} | |
} | |
/* Helper buddy for removing async/await try/catch litter 🗑 */ | |
function O_o(promise) { | |
return promise.then(data => { | |
if (data instanceof Error) { | |
throwNative(data) | |
return [data] | |
} | |
return [null, data] | |
}).catch(error => { | |
throwNative(error) | |
return [error] | |
}) | |
} | |
/* Look ma, no try/catch */ | |
async function usageExample(input) { | |
try { | |
const [ errorOne, dataOne ] = await O_o(myPromise(input)) | |
if (errorOne) { | |
// Handle business logic errors | |
console.log('Business logic error', errorOne) | |
} | |
/* ignore myPromiseTwo business logic errors by omitting first array item */ | |
const [ , dataTwo ] = await O_o(myPromiseTwo('other')) | |
/* handle error or null promise response */ | |
const [ errorThree, dataThree ] = await O_o(myPromiseThree('other')) | |
if (errorThree || !dataThree) { | |
console.log('Business logic error three', errorThree) | |
} | |
// Bail/retry if required data missing | |
if (!dataOne || !dataTwo || !dataThree) { | |
return 'NOPE' | |
} | |
// do stuff with data | |
console.log('myPromise', dataOne) | |
console.log('myPromiseTwo', dataTwo) | |
console.log('myPromiseThree', dataThree) | |
return { | |
dataOne, | |
dataTwo, | |
dataThree | |
} | |
} catch (e) { | |
// Handle native javascript errors here | |
console.log('Native JS error', e) | |
} | |
} | |
/* Promises with callback */ | |
function myPromise(input) { | |
return new Promise((resolve, reject) => { | |
callbacker(input, (error, data) => { | |
if (error) return reject(error) | |
return resolve(data) | |
}) | |
}) | |
} | |
/* Normal promise */ | |
function myPromiseTwo(value) { | |
return Promise.resolve(`myPromiseTwo data ${value}`) | |
} | |
/* Normal promise */ | |
function myPromiseThree() { | |
if (simulateFailure(true)) { | |
console.log('myPromiseThree error triggered') | |
return Promise.resolve( | |
new Error('myPromiseThree business logic error') | |
) | |
} | |
return Promise.resolve('myPromiseThree data') | |
} | |
/* Normal callback */ | |
function callbacker(input, cb) { | |
if (simulateFailure(true)) { | |
console.log('syntaxError error triggered') | |
// unknownThing will throw syntaxError | |
console.log(unknownThing) | |
} | |
return cb(null, { | |
value: businessLogic(input) | |
}) | |
} | |
/* Randomly simulate failures */ | |
function simulateFailure(enable) { | |
if (!enable) return false | |
return (Math.floor(Math.random() * 10) + 1) < 6 | |
} | |
function businessLogic(input) { | |
if (simulateFailure()) { | |
console.log('businessLogic error triggered') | |
throw new Error('Business logic error xyz') | |
} | |
return `${input} fizzbuzz` | |
} | |
/* Run the thing */ | |
usageExample('foobar').then((result) => { | |
console.log('final result', result) | |
}).catch((err) => { | |
console.log('final catch', err) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment