fix: implement Symbol.specics of Promise (#34162)
Close #34105, #33989 PR Close #34162
This commit is contained in:
parent
6b1a47183d
commit
539d8f09e0
|
@ -256,6 +256,8 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
|
||||||
|
|
||||||
const ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }';
|
const ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }';
|
||||||
|
|
||||||
|
const noop = function() {};
|
||||||
|
|
||||||
class ZoneAwarePromise<R> implements Promise<R> {
|
class ZoneAwarePromise<R> implements Promise<R> {
|
||||||
static toString() { return ZONE_AWARE_PROMISE_TO_STRING; }
|
static toString() { return ZONE_AWARE_PROMISE_TO_STRING; }
|
||||||
|
|
||||||
|
@ -374,12 +376,17 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
|
||||||
|
|
||||||
get[Symbol.toStringTag]() { return 'Promise' as any; }
|
get[Symbol.toStringTag]() { return 'Promise' as any; }
|
||||||
|
|
||||||
|
get[Symbol.species]() { return ZoneAwarePromise; }
|
||||||
|
|
||||||
then<TResult1 = R, TResult2 = never>(
|
then<TResult1 = R, TResult2 = never>(
|
||||||
onFulfilled?: ((value: R) => TResult1 | PromiseLike<TResult1>)|undefined|null,
|
onFulfilled?: ((value: R) => TResult1 | PromiseLike<TResult1>)|undefined|null,
|
||||||
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>)|undefined|
|
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>)|undefined|
|
||||||
null): Promise<TResult1|TResult2> {
|
null): Promise<TResult1|TResult2> {
|
||||||
const chainPromise: Promise<TResult1|TResult2> =
|
let C = (this.constructor as any)[Symbol.species];
|
||||||
new (this.constructor as typeof ZoneAwarePromise)(null as any);
|
if (!C || typeof C !== 'function') {
|
||||||
|
C = ZoneAwarePromise;
|
||||||
|
}
|
||||||
|
const chainPromise: Promise<TResult1|TResult2> = new (C as typeof ZoneAwarePromise)(noop);
|
||||||
const zone = Zone.current;
|
const zone = Zone.current;
|
||||||
if ((this as any)[symbolState] == UNRESOLVED) {
|
if ((this as any)[symbolState] == UNRESOLVED) {
|
||||||
(<any[]>(this as any)[symbolValue]).push(zone, chainPromise, onFulfilled, onRejected);
|
(<any[]>(this as any)[symbolValue]).push(zone, chainPromise, onFulfilled, onRejected);
|
||||||
|
@ -395,8 +402,11 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
|
||||||
}
|
}
|
||||||
|
|
||||||
finally<U>(onFinally?: () => U | PromiseLike<U>): Promise<R> {
|
finally<U>(onFinally?: () => U | PromiseLike<U>): Promise<R> {
|
||||||
const chainPromise: Promise<R|never> =
|
let C = (this.constructor as any)[Symbol.species];
|
||||||
new (this.constructor as typeof ZoneAwarePromise)(null as any);
|
if (!C || typeof C !== 'function') {
|
||||||
|
C = ZoneAwarePromise;
|
||||||
|
}
|
||||||
|
const chainPromise: Promise<R|never> = new (C as typeof ZoneAwarePromise)(noop);
|
||||||
(chainPromise as any)[symbolFinally] = symbolFinally;
|
(chainPromise as any)[symbolFinally] = symbolFinally;
|
||||||
const zone = Zone.current;
|
const zone = Zone.current;
|
||||||
if ((this as any)[symbolState] == UNRESOLVED) {
|
if ((this as any)[symbolState] == UNRESOLVED) {
|
||||||
|
|
|
@ -103,11 +103,21 @@ describe(
|
||||||
}).toThrowError('Must be an instanceof Promise.');
|
}).toThrowError('Must be an instanceof Promise.');
|
||||||
});
|
});
|
||||||
|
|
||||||
xit('should allow subclassing', () => {
|
it('should allow subclassing with Promise.specices', () => {
|
||||||
class MyPromise extends Promise<any> {
|
class MyPromise extends Promise<any> {
|
||||||
constructor(fn: any) { super(fn); }
|
constructor(fn: any) { super(fn); }
|
||||||
|
|
||||||
|
static get[Symbol.species]() { return MyPromise; }
|
||||||
}
|
}
|
||||||
expect(new MyPromise(null).then(() => null) instanceof MyPromise).toBe(true);
|
expect(new MyPromise(() => {}).then(() => null) instanceof MyPromise).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Promise.specices should return ZoneAwarePromise', () => {
|
||||||
|
const empty = function() {};
|
||||||
|
const promise = Promise.resolve(1);
|
||||||
|
const FakePromise = ((promise.constructor = {} as any) as any)[Symbol.species] = function(
|
||||||
|
exec: any) { exec(empty, empty); };
|
||||||
|
expect(promise.then(empty) instanceof FakePromise).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should intercept scheduling of resolution and then', (done) => {
|
it('should intercept scheduling of resolution and then', (done) => {
|
||||||
|
|
Loading…
Reference in New Issue