[fix] passing async functions to the Promise constructor#109565
Closed
spalger wants to merge 1 commit intoelastic:masterfrom
Closed
[fix] passing async functions to the Promise constructor#109565spalger wants to merge 1 commit intoelastic:masterfrom
spalger wants to merge 1 commit intoelastic:masterfrom
Conversation
bf10932 to
c0908a8
Compare
c0908a8 to
872fc70
Compare
Contributor
💚 Build SucceededMetrics [docs]Async chunks
Page load bundle
History
To update your PR or re-run it, just comment with: |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
After fixing #109560 I did a little searching and found many cases where we are passing async functions to the
Promiseconstructor without handling the potential of a rejected promise being created by said async function.The following examples show the types of scenarios which are fixed by this PR:
Bad:
In this example if
someAsyncOperation()fails then the error will propagate from its call site to the promise created when thePromise()constructor called the async function. Unfortunately that promise is not accessible by user code so it will always result in an unhandled rejection. There are two ways to fix this, either ensure the hidden promise never rejects by wrapping the whole body of the function in atry/catch, or limit the code which is wrapped in thePromiseconstructor. I think the second approach is more ideal as it keeps the need for aresolve()callback as close to the source of that need as possible:Fixed:
Bad:
The goal of this function is to mutate the data coming back from the resolved promise in some way before returning/resolving to the outside caller. This should instead be done one of two ways:
Fix:
Using an async-IIFE is stylistically similar to the problematic code and properly routes errors in the case that
getObject()rejects and handles possible synchronous errors, likegetObject()not being a function, not returning a promise, or throwing synchronously for some reason.Bad:
Just like the previous example, if
loadSomeData()rejects it's promise the hidden promise created by the Promise constructor will be rejected as the error propagates, but there is no way for us to handle that rejection. In this scenario I modeled the user interaction using an RxJSReplaySubject(1), which is anObservablewhose events can be programmatically customized from the outside and will remember the last value emitted and re-emit with new subscriptions. This might look unnecessarily complicated in my example but in the code where this pattern is used there are many things happening in the same place and the callbacks passed torenderSomethingAndWaitForUserInteraction()are not always constant, so this was a flexible way to model this scenario which has added benefits like being able to process each event produced on theSubject.Fixed: