183 lines
25 KiB
JavaScript
183 lines
25 KiB
JavaScript
|
import { Injectable, NgZone } from '@angular/core';
|
||
|
import { asyncScheduler, Observable, queueScheduler } from 'rxjs';
|
||
|
import { observeOn, subscribeOn, tap } from 'rxjs/operators';
|
||
|
import * as i0 from "@angular/core";
|
||
|
function noop() {
|
||
|
}
|
||
|
/**
|
||
|
* Schedules tasks so that they are invoked inside the Zone that is passed in the constructor.
|
||
|
*/
|
||
|
// tslint:disable-next-line:class-name
|
||
|
export class ɵZoneScheduler {
|
||
|
constructor(zone, delegate = queueScheduler) {
|
||
|
this.zone = zone;
|
||
|
this.delegate = delegate;
|
||
|
}
|
||
|
now() {
|
||
|
return this.delegate.now();
|
||
|
}
|
||
|
schedule(work, delay, state) {
|
||
|
const targetZone = this.zone;
|
||
|
// Wrap the specified work function to make sure that if nested scheduling takes place the
|
||
|
// work is executed in the correct zone
|
||
|
const workInZone = function (state) {
|
||
|
targetZone.runGuarded(() => {
|
||
|
work.apply(this, [state]);
|
||
|
});
|
||
|
};
|
||
|
// Scheduling itself needs to be run in zone to ensure setInterval calls for async scheduling are done
|
||
|
// inside the correct zone. This scheduler needs to schedule asynchronously always to ensure that
|
||
|
// firebase emissions are never synchronous. Specifying a delay causes issues with the queueScheduler delegate.
|
||
|
return this.delegate.schedule(workInZone, delay, state);
|
||
|
}
|
||
|
}
|
||
|
class BlockUntilFirstOperator {
|
||
|
constructor(zone) {
|
||
|
this.zone = zone;
|
||
|
this.task = null;
|
||
|
}
|
||
|
call(subscriber, source) {
|
||
|
const unscheduleTask = this.unscheduleTask.bind(this);
|
||
|
this.task = this.zone.run(() => Zone.current.scheduleMacroTask('firebaseZoneBlock', noop, {}, noop, noop));
|
||
|
return source.pipe(tap({ next: unscheduleTask, complete: unscheduleTask, error: unscheduleTask })).subscribe(subscriber).add(unscheduleTask);
|
||
|
}
|
||
|
unscheduleTask() {
|
||
|
// maybe this is a race condition, invoke in a timeout
|
||
|
// hold for 10ms while I try to figure out what is going on
|
||
|
setTimeout(() => {
|
||
|
if (this.task != null && this.task.state === 'scheduled') {
|
||
|
this.task.invoke();
|
||
|
this.task = null;
|
||
|
}
|
||
|
}, 10);
|
||
|
}
|
||
|
}
|
||
|
// tslint:disable-next-line:class-name
|
||
|
export class ɵAngularFireSchedulers {
|
||
|
constructor(ngZone) {
|
||
|
this.ngZone = ngZone;
|
||
|
this.outsideAngular = ngZone.runOutsideAngular(() => new ɵZoneScheduler(Zone.current));
|
||
|
this.insideAngular = ngZone.run(() => new ɵZoneScheduler(Zone.current, asyncScheduler));
|
||
|
globalThis.ɵAngularFireScheduler || (globalThis.ɵAngularFireScheduler = this);
|
||
|
}
|
||
|
}
|
||
|
ɵAngularFireSchedulers.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: ɵAngularFireSchedulers, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
||
|
ɵAngularFireSchedulers.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: ɵAngularFireSchedulers, providedIn: 'root' });
|
||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: ɵAngularFireSchedulers, decorators: [{
|
||
|
type: Injectable,
|
||
|
args: [{
|
||
|
providedIn: 'root',
|
||
|
}]
|
||
|
}], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
|
||
|
function getSchedulers() {
|
||
|
const schedulers = globalThis.ɵAngularFireScheduler;
|
||
|
if (!schedulers) {
|
||
|
throw new Error(`Either AngularFireModule has not been provided in your AppModule (this can be done manually or implictly using
|
||
|
provideFirebaseApp) or you're calling an AngularFire method outside of an NgModule (which is not supported).`);
|
||
|
}
|
||
|
return schedulers;
|
||
|
}
|
||
|
function runOutsideAngular(fn) {
|
||
|
return getSchedulers().ngZone.runOutsideAngular(() => fn());
|
||
|
}
|
||
|
function run(fn) {
|
||
|
return getSchedulers().ngZone.run(() => fn());
|
||
|
}
|
||
|
export function observeOutsideAngular(obs$) {
|
||
|
return obs$.pipe(observeOn(getSchedulers().outsideAngular));
|
||
|
}
|
||
|
export function observeInsideAngular(obs$) {
|
||
|
return obs$.pipe(observeOn(getSchedulers().insideAngular));
|
||
|
}
|
||
|
export function keepUnstableUntilFirst(obs$) {
|
||
|
const scheduler = getSchedulers();
|
||
|
return ɵkeepUnstableUntilFirstFactory(getSchedulers())(obs$);
|
||
|
}
|
||
|
/**
|
||
|
* Operator to block the zone until the first value has been emitted or the observable
|
||
|
* has completed/errored. This is used to make sure that universal waits until the first
|
||
|
* value from firebase but doesn't block the zone forever since the firebase subscription
|
||
|
* is still alive.
|
||
|
*/
|
||
|
export function ɵkeepUnstableUntilFirstFactory(schedulers) {
|
||
|
return function keepUnstableUntilFirst(obs$) {
|
||
|
obs$ = obs$.lift(new BlockUntilFirstOperator(schedulers.ngZone));
|
||
|
return obs$.pipe(
|
||
|
// Run the subscribe body outside of Angular (e.g. calling Firebase SDK to add a listener to a change event)
|
||
|
subscribeOn(schedulers.outsideAngular),
|
||
|
// Run operators inside the angular zone (e.g. side effects via tap())
|
||
|
observeOn(schedulers.insideAngular)
|
||
|
// INVESTIGATE https://github.com/angular/angularfire/pull/2315
|
||
|
// share()
|
||
|
);
|
||
|
};
|
||
|
}
|
||
|
const zoneWrapFn = (it, macrotask) => {
|
||
|
const _this = this;
|
||
|
// function() is needed for the arguments object
|
||
|
// tslint:disable-next-line:only-arrow-functions
|
||
|
return function () {
|
||
|
const _arguments = arguments;
|
||
|
if (macrotask) {
|
||
|
setTimeout(() => {
|
||
|
if (macrotask.state === 'scheduled') {
|
||
|
macrotask.invoke();
|
||
|
}
|
||
|
}, 10);
|
||
|
}
|
||
|
return run(() => it.apply(_this, _arguments));
|
||
|
};
|
||
|
};
|
||
|
export const ɵzoneWrap = (it, blockUntilFirst) => {
|
||
|
// function() is needed for the arguments object
|
||
|
// tslint:disable-next-line:only-arrow-functions
|
||
|
return function () {
|
||
|
let macrotask;
|
||
|
const _arguments = arguments;
|
||
|
// if this is a callback function, e.g, onSnapshot, we should create a microtask and invoke it
|
||
|
// only once one of the callback functions is tripped.
|
||
|
for (let i = 0; i < arguments.length; i++) {
|
||
|
if (typeof _arguments[i] === 'function') {
|
||
|
if (blockUntilFirst) {
|
||
|
macrotask || (macrotask = run(() => Zone.current.scheduleMacroTask('firebaseZoneBlock', noop, {}, noop, noop)));
|
||
|
}
|
||
|
// TODO create a microtask to track callback functions
|
||
|
_arguments[i] = zoneWrapFn(_arguments[i], macrotask);
|
||
|
}
|
||
|
}
|
||
|
const ret = runOutsideAngular(() => it.apply(this, _arguments));
|
||
|
if (!blockUntilFirst) {
|
||
|
if (ret instanceof Observable) {
|
||
|
const schedulers = getSchedulers();
|
||
|
return ret.pipe(subscribeOn(schedulers.outsideAngular), observeOn(schedulers.insideAngular));
|
||
|
}
|
||
|
else {
|
||
|
return run(() => ret);
|
||
|
}
|
||
|
}
|
||
|
if (ret instanceof Observable) {
|
||
|
return ret.pipe(keepUnstableUntilFirst);
|
||
|
}
|
||
|
else if (ret instanceof Promise) {
|
||
|
return run(() => new Promise((resolve, reject) => ret.then(it => run(() => resolve(it)), reason => run(() => reject(reason)))));
|
||
|
}
|
||
|
else if (typeof ret === 'function' && macrotask) {
|
||
|
// Handle unsubscribe
|
||
|
// function() is needed for the arguments object
|
||
|
// tslint:disable-next-line:only-arrow-functions
|
||
|
return function () {
|
||
|
setTimeout(() => {
|
||
|
if (macrotask && macrotask.state === 'scheduled') {
|
||
|
macrotask.invoke();
|
||
|
}
|
||
|
}, 10);
|
||
|
return ret.apply(this, arguments);
|
||
|
};
|
||
|
}
|
||
|
else {
|
||
|
// TODO how do we handle storage uploads in Zone? and other stuff with cancel() etc?
|
||
|
return run(() => ret);
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiem9uZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvem9uZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUNMLGNBQWMsRUFDZCxVQUFVLEVBRVYsY0FBYyxFQU1mLE1BQU0sTUFBTSxDQUFDO0FBQ2QsT0FBTyxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7O0FBRTdELFNBQVMsSUFBSTtBQUNiLENBQUM7QUFFRDs7R0FFRztBQUNILHNDQUFzQztBQUN0QyxNQUFNLE9BQU8sY0FBYztJQUN6QixZQUFvQixJQUFTLEVBQVUsV0FBZ0IsY0FBYztRQUFqRCxTQUFJLEdBQUosSUFBSSxDQUFLO1FBQVUsYUFBUSxHQUFSLFFBQVEsQ0FBc0I7SUFDckUsQ0FBQztJQUVELEdBQUc7UUFDRCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVELFFBQVEsQ0FBQyxJQUF1RCxFQUFFLEtBQWMsRUFBRSxLQUFXO1FBQzNGLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7UUFDN0IsMEZBQTBGO1FBQzFGLHVDQUF1QztRQUN2QyxNQUFNLFVBQVUsR0FBRyxVQUFxQyxLQUFVO1lBQ2hFLFVBQVUsQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFO2dCQUN6QixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDNUIsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUM7UUFFRixzR0FBc0c7UUFDdEcsaUdBQWlHO1FBQ2pHLCtHQUErRztRQUMvRyxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDMUQsQ0FBQztDQUNGO0FBRUQsTUFBTSx1QkFBdUI7SUFHM0IsWUFBb0IsSUFBUztRQUFULFNBQUksR0FBSixJQUFJLENBQUs7UUFGckIsU0FBSSxHQUFxQixJQUFJLENBQUM7SUFHdEMsQ0FBQztJQUVELElBQUksQ0FBQyxVQUF5QixFQUFFLE1BQXFCO1FBQ25ELE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3RELElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxtQkFBbUIsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBRTNHLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FDaEIsR0FBRyxDQUFDLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUMvRSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVPLGNBQWM7UUFDcEIsc0RBQXNEO1FBQ3RELDJEQUEyRDtRQUMzRCxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ2QsSUFBSSxJQUFJLENBQUMsSUFBSSxJQUFJLElBQUksSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssS0FBSyxXQUFXLEVBQUU7Z0JBQ3hELElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ25CLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO2FBQ2xCO1FBQ0gsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ1QsQ0FBQztDQUNGO0FBS0Qsc0NBQXNDO0FBQ3RDLE1BQU0sT0FBTyxzQkFBc0I7SUFJakMsWUFBbUIsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7UUFDL0IsSUFBSSxDQUFDLGNBQWMsR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFDdkYsSUFBSSxDQUFDLGFBQWEsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsY0FBYyxDQUFDLENBQUMsQ0FBQztRQUN4RixVQUFVLENBQUMscUJBQXFCLEtBQWhDLFVBQVUsQ0FBQyxxQkFBcUIsR0FBSyxJQUFJLEVBQUM7SUFDNUMsQ0FBQzs7bUhBUlUsc0JBQXNCO3VIQUF0QixzQkFBc0IsY0FIckIsTUFBTTsyRkFHUCxzQkFBc0I7a0JBSmxDLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25COztBQWFELFNBQVMsYUFBYTtJQUNwQixNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMscUJBQXlELENBQUM7SUFDeEYsSUFBSSxDQUFDLFVBQVUsRUFBRTtRQUNmLE1BQU0sSUFBSSxLQUFLLENBQ25COzZHQUM2RyxDQUFDLENBQUM7S0FDNUc7SUFDRCxPQUFPLFVBQVUsQ0FBQztBQUNwQixDQUFDO0FBRUQsU0FBUyxpQkFBaUIsQ0FBSSxFQUF5QjtJQUNyRCxPQUFPLGFBQWEsRUFBRSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQzlELENBQUM7QUFFRCxTQUFTLEdBQUcsQ0FBSSxFQUF5QjtJQUN2QyxPQUFPLGFBQWEsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUNoRCxDQUFDO0FBRUQsTUFBTSxVQUFVLHFCQUFxQixDQUFJLElBQW1CO0lBQzFELE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxFQUFFLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQztBQUM5RCxDQUFDO0FBRUQsTUFBTSxVQUFVLG9CQUFvQixDQUFJLElBQW1CO0lBQ3pELE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztBQUM3RCxDQUFDO0FBRUQsTUFBTSxVQUFVLHNCQUFzQixDQUFJLElBQW1CO0lBQzNELE1BQU0sU0FBUyxHQUFHLGFBQWEsRUFBRSxDQUFDO0lBQ2xDLE9BQU8sOEJBQThCLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUMvRCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsOEJBQThCLENBQUMsVUFBa0M7S
|