-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/async parse args experiment #1913
Feature/async parse args experiment #1913
Conversation
What about checking for whether |
Good question. From that point of view, either the change is breaking or non-breaking. It does not matter whether One way of shipping it in a minor version would be to make it opt-in, before making it always-on in the next major version. A possible fallback is to just add an example file for now! It all looked nice and easy for limited use case like: #1900 (comment) |
Yeah, I know it is going to be breaking in the end anyway, I just meant that by checking for |
Added support for multiple calls to |
I think we probably only need to support built-in async. If the user wants some variant of the promise resolving they can move the async processing to a hook, so not blocked. Less clever but less magic too. |
lib/command.js
Outdated
} | ||
} | ||
|
||
if (thenable(result)) result.catch(refineError); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refineError()
throws, so there will be an unhandled promise rejection. The result of the catch()
call needs to be assigned to result
to prevent it.
But if previous
is already thenable, it is better to call catch()
in the previous.then()
callback (and return the result). Otherwise, catch()
might be called on an already failed promise chain in which an error has already been caught and rethrown (because that is what refineError()
does), so refineError()
would be called again which does not make sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I think calling result.then(x => x, refineError)
instead of result.catch(refineError)
is more robust.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The result of the
catch()
call needs to be assigned toresult
Oops, yes, good catch.
Otherwise,
catch()
might be called on an already failed promise chain in which an error has already been caught and rethrown
I think this is correct pattern, but I'll try it before explaining my reasoning.
Also, I think calling result.then(x => x, refineError) instead of result.catch(refineError) is more robust.
Because we only test for .then()
? Yes, I have thought about that in past and then forgot. I want to just assume they are promise-like since the primary use-case is for async, but it isn't hard to only rely on then
and cover a few more edge uses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if
previous
is already thenable, it is better to callcatch()
in theprevious.then()
callback (and return the result). Otherwise,catch()
might be called on an already failed promise chain in which an error has already been caught and rethrown (because that is whatrefineError()
does), sorefineError()
would be called again which does not make sense.
Took me a while to understand this. I was expecting a long catch chain, but see it can be avoided. 👍
But there are use cases where the user might not want that, so making chaining configurable now suggests itself. That is why I kept |
But all currently available hooks are only called after the available thenable option and argument values are resolved, so this does not seem like a good option to me. The user would have no access to the promises returned by async parsers at all, even when calling In its simplest non-magical form (independent from whether
But again, an explanation why a little "magic" is meaningful is given in #1915, with additional details in this comment. |
Yes, the work-around I was suggesting for what are hopefully rare cases was use synchronous I understand this is not the flexibility you have proposed. |
Did not get it back then, but I see what you mean now 👍 |
This is pretty cool, but I am not happy enough with it:
User can achieve most of the functionality themselves fairly easily because they know how their program is constructed. I am currently thinking async action handlers would be a neat example, but not a great built-in feature. |
This is an experiment based on concepts in #1902 to support async Option.parseArgs and Arguments.parseArgs. Blindly store the return value from async calls to parseArgs as usual (although actually a pending promise), and then settle the promises in a batch before proceeding to next stage of parsing. In particular, settle the promises before calling user hooks or action handler so client code is unlikely to see the promises.
Simplified approach compared to #1902, here:
handling previous value promises from repeated calls to parseArgs left to clientReminder to add co-author credit if proceed with this PR.