GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat(zones)!: deliver Observable read values as microtasks by armando-navarro · Pull Request #3833 · angular/angularfire

Conversation

@armando-navarro

@armando-navarro armando-navarro commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

Checklist

  • Issue number for this PR: Deliver Observable read values as microtasks instead of after a timer #3832
  • Docs included?: no, the upgrade-guide entry lands in a separate docs PR.
  • Test units included?: yes
  • Breaking change?: yes
  • In a clean directory, yarn install, yarn test run successfully? yes, as npm ci and npm test

Description

Builds the insideAngular scheduler in src/zones.ts over a private AsapScheduler instance instead of rxjs's asyncScheduler, so every value from an Observable-returning read reaches the subscriber at the next microtask checkpoint instead of after a setInterval turn.

  • The instance is AngularFire's own rather than rxjs's shared asapScheduler because the shared one runs every action scheduled in a turn as one batch and cancels the rest of the batch when one action throws, which would let another library's action drop a delivery.
  • AsapScheduler and AsapAction come from rxjs/internal/scheduler/, a path rxjs 7.8 lists in its exports map but keeps under internal.
  • Nothing else in the wrapper changes: Promise-returning and callback-taking wrappers never used this scheduler.

What this grants, measured on Angular 22.2 zone.js and zoneless apps, before and after:

  • Values arrive before a zero-delay timer registered when the source emitted, in every run: a synthetic source in Chrome and Firefox, and collectionData against the Firestore emulator and the compat authState against the Auth emulator in Chrome.
  • A server render reports stable about 1 ms sooner after Firestore's last callback.

What does not change:

  • The DOM updates on delivery and the subscriber runs inside the Angular zone.
  • zone.js ticks once per value and zoneless once per burst.
  • Order is preserved.

What upgrading apps may notice:

  • A test that waits only for microtasks (a few awaited promises, vitest fake timers without advancing, fakeAsync with flushMicrotasks() alone) now sees a value whose source emits in a microtask, as Auth and a promise-based mock do. Firestore hands its snapshots over in a setTimeout, so Firestore reads still need a timer to advance. Tests that advance timers are unchanged.
  • Code that registers its own setTimeout when a read emits sees that timer run after the value arrives, not before.
  • In a zoneless server render, a value arriving between the app reporting stable and serialization now reaches a hand-written TransferState entry but not the HTML, because the zoneless change-detection pass is itself a later timer. Before this change such a value reached neither.
  • The compat AngularFireAuth streams move with the modular reads. Compat AngularFireFunctions and AngularFireMessaging only hand over their SDK instance through this scheduler, and compat Database and Firestore do not use it.

Verification:

  • New spec src/zones.spec.ts: a wrapped Observable's value arrives asynchronously, inside the Angular zone, and before a zero-delay timer registered when the source emitted, and the delivery scheduler is an AsapScheduler that is not rxjs's shared instance. Fails on main, passes here.
  • npm run lint, npm run test:node, npm run test:chrome-headless and npm run test:firefox-headless pass on the branch.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@armando-navarro
feat(zones)!: deliver Observable read values as microtasks
a2188c1
The insideAngular scheduler was built over asyncScheduler, so every
value from an Observable read reached its subscriber one setInterval
turn after Firebase handed it over. A private AsapScheduler instance
delivers at the next microtask checkpoint instead, still never
synchronously. It is private because rxjs's shared asapScheduler
cancels the rest of a batch when one action throws.

Measured on Angular 22.2 apps, zone.js and zoneless: delivery moves
ahead of a zero-delay timer in every run, change detection and
ordering are unchanged, and a server render reports stable about a
millisecond sooner. The compat AngularFireAuth streams move too.

BREAKING CHANGE: Observable reads (collectionData, docData, authState,
user, objectVal, listVal and the rest) now deliver at the next
microtask checkpoint instead of after a zero-delay timer. A test that
waits only for microtasks now sees a value whose source emits in a
microtask. Code that orders its own setTimeout against a read's value
sees the timer run after the value, not before. In a zoneless server
render, a value arriving between stability and serialization reaches
a hand-written TransferState entry but not the HTML.

Fixes angular#3832
@armando-navarro
armando-navarro requested a review from tyler-reitz October 30, 2026 17:55
@armando-navarro armando-navarro added breaking change Upgrading apps must change something. Call it out in the release notes bump: major Size of the change: breaking, ships only in a major release comp: compat Compatibility layer for the pre-modular API (src/compat). comp: ssr Server-side rendering, hydration, @angular/ssr interop. comp: zones Change detection / zone.js / zoneless. type: feature New capability or enhancement. labels Oct 30, 2026
tyler-reitz
tyler-reitz approved these changes Nov 2, 2026
View reviewed changes

@tyler-reitz tyler-reitz left a comment

Copy link
Copy Markdown
Collaborator

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.

Approving. I confirmed the new spec fails on both counts when asyncScheduler is swapped back in, and passes on the branch. One ask before rc.1: the body says the upgrade-guide entry lands in a separate docs PR, but there isn't one yet and #3835 doesn't mention it. Could you add the entry to #3835 so the breaking change ships with its migration note?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
armando-navarro added a commit to armando-navarro/angularfire that referenced this pull request Nov 4, 2026
@armando-navarro
docs: describe microtask delivery in the v22 upgrade guide
40b07fa
angular#3833 moves every Observable read from a setInterval timer to the next
microtask checkpoint. As a breaking change it needs a section in the
upgrade guide: which tests now see a value they used to wait for, the
setTimeout ordering flip, and the zoneless server render case for
hand-written TransferState entries.

Refs angular#3832
@armando-navarro

armando-navarro commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, Tyler. I've added the docs update in a commit on #3835, a new section "Observable reads deliver as microtasks" in docs/version-22-upgrade.md with the test-timing, setTimeout ordering and zoneless server render notes from this PR's description.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@armando-navarro armando-navarro mentioned this pull request Nov 4, 2026
docs: document the 22.0.0-rc.1 changes #3835
Open
@armando-navarro
Merge branch 'main' into a41-microtask-delivery
aa54d4f
@armando-navarro
armando-navarro enabled auto-merge (squash) November 4, 2026 17:40
@armando-navarro
armando-navarro merged commit 7206aef into angular:main Nov 4, 2026
25 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@armando-navarro armando-navarro added this to the 22.0.0-rc.1 milestone Nov 4, 2026
This was referenced Nov 5, 2026
fix(core): wrap observer-object handlers like functions, and let a wrapped promise settle after teardown #3829
Merged
Remove a callback read's pending task right after the callback instead of one setTimeout(fn, 0) later #3836
Closed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@tyler-reitz tyler-reitz tyler-reitz approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

breaking change Upgrading apps must change something. Call it out in the release notes bump: major Size of the change: breaking, ships only in a major release comp: compat Compatibility layer for the pre-modular API (src/compat). comp: ssr Server-side rendering, hydration, @angular/ssr interop. comp: zones Change detection / zone.js / zoneless. type: feature New capability or enhancement.

Projects

None yet

Milestone

22.0.0-rc.1

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@armando-navarro @tyler-reitz
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.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.