3 ms·
try { // Parallel execution of independent operations const [config, userData] = await Promise.all([ readFile('config.json', 'utf8'), fetch(
by joaohaas 1y ago
try {
// Parallel execution of independent operations
const [config, userData] = await Promise.all([
readFile('config.json', 'utf8'),
fetch('/api/user').then(r => r.json())
]);
...
} catch (error) {
// Structured error logging with context
...
}
This might seem fine at a glance, but a big grip I have with node/js async/promise helper functions is that you can't differ which promise returned/threw an exception.
In this example, if you wanted to handle the `config.json` file not existing, you would need to somehow know what kind of error the `readFile` function can throw, and somehow manage to inspect it in the 'error' variable.
This gets even worse when trying to use something like `Promise.race` to handle promises as they are completed, like:
const result = Promise.race([op1, op2, op3]);
You need to somehow embed the information about what each promise represents inside the promise result, which usually is done through a wrapper that injects the promise value inside its own response... which is really ugly.
- SebastianKra 1y agoIMO when you do control-flow in catch blocks, you're fighting against the language. You lose Typescripts type-safety, and the whole "if e instanceof ... else throw e"-dance creates too much boilerplate. If the config file not existing is a handleable case, then write a "loadConfig" function that returns undefined.
- augusto-moura 1y agoYou are probably looking for `Promise.allSettled`[1]. Which, to be fair, becomes quite convulated with destructuring (note that the try-catch is not necessary anymore, since allSettled doesn't "throw"): // Parallel execution of independent operations const [ { value: config, reason: configError }, { value: userData, reason: userDataError }, ] = await Promise.allSettled([ readFile('config.json', 'utf8'), fetch('/api/user').then(r => r.json()) ]); if (configError) { // Error with config } if (userDataError) { // Error with userData } When dealing with multiple parallel tasks that I care about their errors individually, I prefer to start the promises first and then await for their results after all of them are started, that way I can use try catch or be more explicit about resources: // Parallel execution of independent operations const configPromise = readFile('config.json', 'utf8') const userDataPromise = fetch('/api/user').then(r => r.json()) let config; try { config = await configPromise } catch (err) { // Error with config } let userData; try { userData = await userDataPromise } catch (err) { // Error with userData } Edit: added examples for dealing with errors with allSettled [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...