-
-
Save tjconcept/69994c78c8f5b8008258353292787519 to your computer and use it in GitHub Desktop.
class Rejection { | |
constructor(reason) { | |
this.reason = reason | |
} | |
} | |
export default function using(...args) { | |
const lastIdx = args.length - 1 | |
const fn = args[lastIdx] | |
if (typeof fn !== 'function') { | |
throw new Error('Missing expected function argument') | |
} | |
if (lastIdx === 0) { | |
throw new Error('At least two arguments must be passed') | |
} | |
const wrapped = Array(lastIdx) | |
for (let i = 0; i < lastIdx; i++) { | |
wrapped[i] = args[i].catch((err) => new Rejection(err)) | |
} | |
return Promise.all(wrapped).then((results) => { | |
const err = results.find((r) => r instanceof Rejection) | |
if (err !== undefined) { | |
return Promise.reject(err.reason) | |
} else { | |
return fn(...results) | |
} | |
}) | |
} |
That's odd, isn't it?
You are right, it works when executed in shell.
Ah, I think, I get it. It's probably because .then(() => args[i])
never runs in case an early promise rejects..
Ah, I think, I get it. It's probably because
.then(() => args[i])
never runs in case an early promise rejects..
And so, I think in such case the later rejects would be runaways?
I guess it is also kind of a problem.. You would be silencing any potential error from latter promises.
I guess it is also kind of a problem.. You would be silencing any potential error from latter promises.
Hehe, not an issue with my beast :D
I fixed it, I think.
The only deficiency, that could be fixed, would be to "reject earlier". That is, if a value rejects, and all values to the left of it has resolved, reject straight away.
However, if the primary use case is servers, the "common case" would be for all values to resolve, and then this is as optimal as it gets. I think it would be way more complicated to "reject early" too.
Just like the original join
(from Bluebird) and the native Promise.all
, there's the trade-off that you must accept silencing all other rejections. Only in super edge cases is that an issue, but imagine a bug that occurs in your second parameter only when the first one also rejects, e.g. a syntax error. You'd never find it and it could lead to a memory leak or data corruption:
const a = Promise.reject(new Error('Oops!'))
const b = a.then(
() => 'Hurra!',
(err) => FallbackPlan()
)
join(a, b, console.log)
You'll never see that FallbackPlan
is not defined, or worse if it fails half-way and doesn't clean up and leaks.
So, if you're the pedantic type, you'd probably not use join
or Promise.all
if exceptions are part of your flow control for operational loads. All code can do that, but it may be too cumbersome.
That's odd, isn't it?