`ɵzoneWrap` ignores a handler passed as an observer object, and holds a wrapped promise forever once its injector is destroyed
Les mainteneurs répondent en général sous 3 jours
Évaluation
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Accessibilité débutants
- 25/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- À l'abandon
- Stack technique
- angular, firebase, typescript
- Domaine
- frontend
Piste de recherche
Start by reading src/zones.ts, where ɵzoneWrap handles callbacks and promises. Reproduce the observer-object and destroyed-injector cases described in the issue, then check that object handlers receive the same task, injection-context and zone behavior as function handlers, and that wrapped promises settle after injector destruction. A linked pull request is already open.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Version info
Angular: 22.2
Firebase: 12.19.0
AngularFire: 22.0.0-rc.0, and main
Description
Two defects in ɵzoneWrap (src/zones.ts), the function the generated @angular/fire/* wrappers go through.
1. A handler passed as an object is not wrapped. Firebase accepts a subscription handler either as a function, onSnapshot(ref, snapshot => ...), or as an observer object, onSnapshot(ref, { next: snapshot => ... }). The wrapper rewrites an argument only when typeof is 'function', so the object form reaches the SDK untouched:
- No pending task is registered, so server rendering does not wait for the first value.
inject()throws inside the handler, because nothing re-enters the injection context.- In a zone.js app the handler runs outside the Angular zone, because the wrapper calls Firebase inside
runOutsideAngularand then never brings the object's members back in. The unwrapped Firebase call made from in-zone code keeps its handler in the zone, so the wrapper makes the object form worse than not wrapping at all.
Eleven wrapped functions accept the object form: onAuthStateChanged, onIdTokenChanged, onTokenChanged, onSnapshot, onSnapshotResume, onSnapshotsInSync, onMessage, onRegistered, onUnregistered, onConfigUpdate (which accepts only the object form) and data-connect's subscribe (whose object uses onNext, onErr and onComplete). The three messaging functions are generated with blockUntilFirst: false, so the pending task point does not apply to them.
2. A wrapped promise never settles after its injector is destroyed.
- When a wrapped call returns a Promise, the wrapper resolves its own promise through
runInInjectionContext(injector, () => run(() => resolve(value))). - Neither layer reaches the caller: a
.thencallback runs as a later microtask after the injection context is torn down, and zone.js runs it in the zone where.thenwas attached, not whereresolvewas called. - The one thing the layers do is throw:
runInInjectionContextchecksassertNotDestroyed, so when the Firebase promise settles afterApplicationRef.destroy()or aTestBedreset, the callback throwsNG0205beforeresolveruns and the caller's promise never settles.
How to reproduce these conditions
On a zone.js Angular 22.2 app and a zoneless one, against the Firestore emulator, call the real functions through ɵzoneWrap the way a constructor does, inside the Angular zone and an injection context, and record inside the handler whether a pending task was registered, whether inject() works and whether NgZone.isInAngularZone() is true:
onSnapshot(ref, { next, error })andonSnapshotsInSync(firestore, { next, error }): no task in either app,inject()throws in both, and in the zone.js app the handler runs outside the Angular zone. A plain property written from the handler does not render there, in a component with default change detection.onSnapshot(ref, next), the function form: one task, released when the handler ran,inject()works, and in the zone.js app the handler runs inside the zone.- The unwrapped
onSnapshotwith either form of handler, called from the same place:inject()throws, but in the zone.js app the handler stays inside the zone.
For the promise defect, a spec: wrap a function that resolves after 20 ms with ɵzoneWrap(fn, true), call it inside TestBed.runInInjectionContext, call TestBed.resetTestingModule(), then await the returned promise. It never settles and the spec times out after 5 seconds.
Expected behavior
A handler passed as an observer object gets what a handler passed as a function gets: the pending task, the Angular zone and a working inject(). A wrapped promise settles whenever the Firebase promise settles.
Actual behavior
The object form gets none of the three, and a wrapped promise that settles after its injector is destroyed never settles.
- Langage dominant
- TypeScript
- Étoiles
- 7.8k
- Forks
- 2.2k
- Merge moyen
- 2 j 12 h
- PR mergées (30 j)
- 24
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de angular/angularfire
-
Document the 22.0.0-rc.1 changesPeut-être pris @armando-navarro l’a pris il y a 2 jours. Ouvertecomp: docs type: chore
Difficulté 3/5 Une demi-journée Accessibilité débutants 18/100
angular/angularfire#3834 ·
Les mainteneurs répondent en général sous 3 jours
-
comp: compat comp: ssr comp: zones type: feature version: current (v17+)
Difficulté 3/5 1-2 jours Accessibilité débutants 74/100
angular/angularfire#3832 ·
Les mainteneurs répondent en général sous 3 jours
-
Accept firebase 13 in @angular/fire 22Peut-être pris @armando-navarro l’a pris il y a 3 jours. Ouvertecomp: core comp: schematics type: feature
Difficulté 4/5 3-5 jours Accessibilité débutants 25/100
angular/angularfire#3830 ·
Les mainteneurs répondent en général sous 3 jours
-
Eleven wrapped callbacks and remote-config `isSupported` hold the app unstable until something that may never happenPeut-être pris @armando-navarro l’a pris il y a 4 jours. Ouvertecomp: app-check comp: core comp: database comp: remote-config comp: ssr comp: zones type: bug version: current (v17+)
Difficulté 4/5 3-5 jours Accessibilité débutants 48/100
angular/angularfire#3826 ·
Les mainteneurs répondent en général sous 3 jours
-
comp: compat comp: firestore comp: storage type: chore
Difficulté 4/5 3-5 jours Accessibilité débutants 48/100
angular/angularfire#3822 ·
Les mainteneurs répondent en général sous 3 jours
Toutes les issues de angular/angularfire
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
Les mainteneurs répondent en général sous 1 jour
-
ready-for-agent
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
LucasSantana-Dev/Lucky#2951 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
danielmiessler/LifeOS#2567 ·
Les mainteneurs répondent en général sous 9 jours
-
refactor(react-pi): classify base64 images with core's parseBase64Peut-être pris @jimmyallinai l’a pris aujourd’hui. Ouvertemaintenance
Difficulté 2/5 1-3 heures Accessibilité débutants 62/100
assistant-ui/assistant-ui#10293 · 2 commentaires · 1 réaction ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 70/100
brijeshb42/monaco-vim#175 ·