1
1
/* eslint-disable @typescript-eslint/ban-ts-comment */
2
- import { Injectable , NgZone } from "@angular/core" ;
2
+ import {
3
+ ExperimentalPendingTasks ,
4
+ Injectable ,
5
+ NgZone ,
6
+ inject ,
7
+ } from "@angular/core" ;
3
8
import {
4
9
Observable ,
5
10
Operator ,
@@ -48,17 +53,16 @@ export class ɵZoneScheduler implements SchedulerLike {
48
53
}
49
54
50
55
class BlockUntilFirstOperator < T > implements Operator < T , T > {
51
- // @ts -ignore
52
- private task : MacroTask | null = null ;
53
-
54
- constructor ( private zone : any ) { }
56
+ constructor (
57
+ private zone : any ,
58
+ private pendingTasks : ExperimentalPendingTasks
59
+ ) { }
55
60
56
61
call ( subscriber : Subscriber < T > , source : Observable < T > ) : TeardownLogic {
57
- const unscheduleTask = this . unscheduleTask . bind ( this ) ;
58
- // @ts -ignore
59
- this . task = this . zone . run ( ( ) =>
60
- Zone . current . scheduleMacroTask ( "firebaseZoneBlock" , noop , { } , noop , noop )
61
- ) ;
62
+ const taskDone = this . zone . run ( ( ) => this . pendingTasks . add ( ) ) ;
63
+ // maybe this is a race condition, invoke in a timeout
64
+ // hold for 10ms while I try to figure out what is going on
65
+ const unscheduleTask = ( ) => setTimeout ( taskDone , 10 ) ;
62
66
63
67
return source
64
68
. pipe (
@@ -71,17 +75,6 @@ class BlockUntilFirstOperator<T> implements Operator<T, T> {
71
75
. subscribe ( subscriber )
72
76
. add ( unscheduleTask ) ;
73
77
}
74
-
75
- private unscheduleTask ( ) {
76
- // maybe this is a race condition, invoke in a timeout
77
- // hold for 10ms while I try to figure out what is going on
78
- setTimeout ( ( ) => {
79
- if ( this . task != null && this . task . state === "scheduled" ) {
80
- this . task . invoke ( ) ;
81
- this . task = null ;
82
- }
83
- } , 10 ) ;
84
- }
85
78
}
86
79
87
80
@Injectable ( {
@@ -90,6 +83,7 @@ class BlockUntilFirstOperator<T> implements Operator<T, T> {
90
83
export class ɵAngularFireSchedulers {
91
84
public readonly outsideAngular : ɵZoneScheduler ;
92
85
public readonly insideAngular : ɵZoneScheduler ;
86
+ public readonly pendingTasks = inject ( ExperimentalPendingTasks ) ;
93
87
94
88
constructor ( public ngZone : NgZone ) {
95
89
// @ts -ignore
@@ -149,7 +143,9 @@ export function ɵkeepUnstableUntilFirstFactory(
149
143
return function keepUnstableUntilFirst < T > (
150
144
obs$ : Observable < T >
151
145
) : Observable < T > {
152
- obs$ = obs$ . lift ( new BlockUntilFirstOperator ( schedulers . ngZone ) ) ;
146
+ obs$ = obs$ . lift (
147
+ new BlockUntilFirstOperator ( schedulers . ngZone , schedulers . pendingTasks )
148
+ ) ;
153
149
154
150
return obs$ . pipe (
155
151
// Run the subscribe body outside of Angular (e.g. calling Firebase SDK to add a listener to a change event)
@@ -165,19 +161,15 @@ export function ɵkeepUnstableUntilFirstFactory(
165
161
// @ts -ignore
166
162
const zoneWrapFn = (
167
163
it : ( ...args : any [ ] ) => any ,
168
- macrotask : MacroTask | undefined
164
+ taskDone : VoidFunction | undefined
169
165
) => {
170
166
// eslint-disable-next-line @typescript-eslint/no-this-alias
171
167
const _this = this ;
172
168
// function() is needed for the arguments object
173
169
return function ( ) {
174
170
const _arguments = arguments ;
175
- if ( macrotask ) {
176
- setTimeout ( ( ) => {
177
- if ( macrotask . state === "scheduled" ) {
178
- macrotask . invoke ( ) ;
179
- }
180
- } , 10 ) ;
171
+ if ( taskDone ) {
172
+ setTimeout ( taskDone , 10 ) ;
181
173
}
182
174
return run ( ( ) => it . apply ( _this , _arguments ) ) ;
183
175
} ;
@@ -187,26 +179,18 @@ export const ɵzoneWrap = <T = unknown>(it: T, blockUntilFirst: boolean): T => {
187
179
// function() is needed for the arguments object
188
180
return function ( ) {
189
181
// @ts -ignore
190
- let macrotask : MacroTask | undefined ;
182
+ let taskDone : VoidFunction | undefined ;
191
183
const _arguments = arguments ;
192
- // if this is a callback function, e.g, onSnapshot, we should create a microtask and invoke it
184
+ // if this is a callback function, e.g, onSnapshot, we should create a pending task and complete it
193
185
// only once one of the callback functions is tripped.
194
186
for ( let i = 0 ; i < arguments . length ; i ++ ) {
195
187
if ( typeof _arguments [ i ] === "function" ) {
196
188
if ( blockUntilFirst ) {
197
189
// @ts -ignore
198
- macrotask ||= run ( ( ) =>
199
- Zone . current . scheduleMacroTask (
200
- "firebaseZoneBlock" ,
201
- noop ,
202
- { } ,
203
- noop ,
204
- noop
205
- )
206
- ) ;
190
+ taskDone ||= run ( ( ) => getSchedulers ( ) . pendingTasks . add ( ) ) ;
207
191
}
208
192
// TODO create a microtask to track callback functions
209
- _arguments [ i ] = zoneWrapFn ( _arguments [ i ] , macrotask ) ;
193
+ _arguments [ i ] = zoneWrapFn ( _arguments [ i ] , taskDone ) ;
210
194
}
211
195
}
212
196
const ret = runOutsideAngular ( ( ) => ( it as any ) . apply ( this , _arguments ) ) ;
@@ -234,15 +218,11 @@ export const ɵzoneWrap = <T = unknown>(it: T, blockUntilFirst: boolean): T => {
234
218
)
235
219
)
236
220
) ;
237
- } else if ( typeof ret === "function" && macrotask ) {
221
+ } else if ( typeof ret === "function" && taskDone ) {
238
222
// Handle unsubscribe
239
223
// function() is needed for the arguments object
240
224
return function ( ) {
241
- setTimeout ( ( ) => {
242
- if ( macrotask && macrotask . state === "scheduled" ) {
243
- macrotask . invoke ( ) ;
244
- }
245
- } , 10 ) ;
225
+ setTimeout ( taskDone , 10 ) ;
246
226
return ret . apply ( this , arguments ) ;
247
227
} ;
248
228
} else {
0 commit comments