Repository navigation
Conversation
With validateAsync({debounce}), a value change keeps the previous async
result until effects run: pending() is false, invalid() reflects the
old value, and a submit() in the same task acts on it. The cause is in
core debounced(), which turns loading only inside its effect, so any
chain(debounced(...)) user sees the same stale state.
Add forms and core specs that read state in the same task as the write,
plus a triage note with the root cause, measurements, and fix options.
The specs fail until a fix lands. The note is for review and isn't
meant to be merged.
Member
|
Going to close the PRs as they're won't me merged as is. Let's move the discussions to the issues. |
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.
Issue #71636 | Triage note | Forms spec | Core spec | Stuck fix #71414
Why the change
This adds failing specs showing that a debounced async validator keeps its old result instead of reporting
pendingright after a value change, so that we can agree on a fix in@angular/corebefore I write it.Special things to note
@angular/corehas no snapshot-based chaining primitive, and objected to keeping the previous settled value while debouncing. Its author replied that it "seems to be unfixable without breaking changes or creating a new API". Option A follows the review: it removes the staleresolvedstate in coredebounced()itself, for everychain(debounced(...))user.Change outline
What this PR adds
Where the stale state comes from
State read in the same task as
value.set('VALID'), today:After option A:
Recommended fix:
debounced()reportsloadingas soon as its source changesloadingbefore any wait has started. With the old guard, a source that changes toundefined, which forms uses when validation is skipped, would matchpendingValueand stayloadingforever.chain(debounced(...))resource right after a write getsloadingas well.waitfunction that returnsundefinedshowsloadinguntil effects flush. Templates don't see it.chain(debounced(...)), a read in the same task as the write throwsLOADINGwith option A, and returns the stale value today. Both throw afterTestBed.tick(). Factories built withresource()aren't affected.Alternatives
validateAsync()treats a params mismatch as pendingResourceParamsStatus.LOADINGwhile the debounced value differs from the paramsawait injector.get(ApplicationRef).whenStable()inexecuteDecisions for maintainers
debounced()contract. Shouldstatus()turnloadingat the moment the source changes? Thedebounced()guide says that it "tells you whether a new value is still pending".loadingstate acceptable for awaitfunction that returnsundefined? The alternative is to reportloadingonly for a numericwait, which leaves custom asyncwaitfunctions with today's window.PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
Does this PR introduce a breaking change?