Proposal for Promise.prototype.flatten
The term "flatten" or "flatmap" has also been used to refer to "flattening" a nested array; and/or "flattening" (output) of a potentially (arbitrarily) nested data structure (synchronous and asynchronous input/output).
"easier to read" is subjective; depends on the expectations of the reader. try..catch blocks could be considered explicitly "easier to read" by the names used: "try"; "catch".
The requirement appears to be a "reflect" pattern? E.g., see this answer stackoverflow.com/a/31424853 at Wait until all ES6 promises complete, even rejected promises
const reflect = p => p.then(v => ({v, status: "fulfilled" }),
e => ({e, status: "rejected" }));
reflect(promise).then((v => {
console.log(v.status);});
See also tc39/proposal-promise-allSettled.
Is the expected result to write less code and handle exceptions implicitly?
Would this not work?
async function test(promise1, promise2, promise3) {
const val1 = await promise1.catch(); // ignore exceptions
const [val2, val3] = [] = await Promise.all([promise2, promise3]).catch();
await Promise.all([promise1, promise2, promise3]); // throw to caller
return val1 + val2 + val3;
}
Hello,
I oppose this proposal.
In my opinion, mixing normal exceptions (promise rejections) with
result-error-tuples is rather inconsistent than a more consistent
interface. The only thing it might interface better with are
node.js-style callbacks, but we already deprecated those in favour of
promises.
if (err) throw err;
is reminiscent of this old style, it's no longer
necessary to explicitly re-throw with modern syntax.
It's not even simpler, or better to read. The example you gave could easier be written as
async function test(promise1, promise2, promise3) {
const val1 = await promise1.catch(err => void err); // ignore exceptions
const [val2, val3] = await Promise.all([promise2, promise3]); // throw to caller
return val1 + val2 + val3;
}
(Notice also that no default value for the destructuring is necessary,
which is a rather error-prone part of your snippet). Using catch
forces the programmer into explicitly providing a default value (even if
undefined
), which could go unnoticed otherwise.
Can you please add an example where using .flatten()
actually
introduces an advantage?
If one needs a more powerful error handling approach, you should use
then
with two callbacks. (Getting a try-catch-else syntax
stackoverflow.com/questions/4872170/javascript-try-catch-else-finally-like-python-java-ruby-etc for that would be nice, though).
As already mentioned, the name flatten
is ill-suited for this method.
If you absolutely need this functionality, use .then(r=>[,r],e=>[e])
in your code, or put it inside a helper function. (Or use one from a library like scopsy/await-to-js).
We do not need this as a method in the EcmaScript standard.
asilvas/proposal-promise-flatten
Looking for interest, and TC39 champion.
The basic idea is to provide a simpler, more consistent interface, and easier to read code over using try/catches for async code paths. Regardless of which errors are handled or ignored, it's treated as nothing more than another input in the result, not all that dissimilar to callbacks.
async function test(promise1, promise2, promise3) { const [, val1] = await promise1.flatten(); // ignore exceptions const [err, [val2, val3] = []] = await Promise.all([promise2, promise3]).flatten(); if (err) throw err; // throw to caller return val1 + val2 + val3; }
Original topic that spurred interest in this pattern: twitter.com/DavidWells/status/1119729914876284928
Spec discussions: twitter.com/Aaron_Silvas/status/1120721934730137601
Thanks,
Aaron