Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit d77ffd9

Browse files
committed
fix(promise): can set native promise after loading zone.js
1 parent b9c0d9c commit d77ffd9

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

lib/common/promise.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,44 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
330330
ZoneAwarePromise['all'] = ZoneAwarePromise.all;
331331

332332
const NativePromise = global[symbolPromise] = global['Promise'];
333+
const ZONE_AWARE_PROMISE = Zone.__symbol__('ZoneAwarePromise');
334+
335+
let desc = Object.getOwnPropertyDescriptor(global, 'Promise');
336+
if (!desc || desc.configurable) {
337+
desc && delete desc.writable;
338+
desc && delete desc.value;
339+
if (!desc) {
340+
desc = {configurable: true, enumerable: true};
341+
}
342+
desc.get = function() {
343+
// if we already set ZoneAwarePromise, use patched one
344+
// otherwise return native one.
345+
return global[ZONE_AWARE_PROMISE] ? global[ZONE_AWARE_PROMISE] : global[symbolPromise];
346+
};
347+
desc.set = function(NewNativePromise) {
348+
if (NewNativePromise === ZoneAwarePromise) {
349+
// if the NewNativePromise is ZoneAwarePromise
350+
// save to global
351+
global[ZONE_AWARE_PROMISE] = NewNativePromise;
352+
} else {
353+
// if the NewNativePromise is not ZoneAwarePromise
354+
// for example: after load zone.js, some library just
355+
// set es6-promise to global, if we set it to global
356+
// directly, assertZonePatched will fail and angular
357+
// will not loaded, so we just set the NewNativePromise
358+
// to global[symbolPromise], so the result is just like
359+
// we load ES6 Promise before zone.js
360+
global[symbolPromise] = NewNativePromise;
361+
if (!NewNativePromise.prototype[symbolThen]) {
362+
patchThen(NewNativePromise);
363+
}
364+
api.setNativePromise(NewNativePromise);
365+
}
366+
};
367+
368+
Object.defineProperty(global, 'Promise', desc);
369+
}
370+
333371
global['Promise'] = ZoneAwarePromise;
334372

335373
const symbolThenPatched = __symbol__('thenPatched');

lib/zone.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ interface _ZonePrivate {
322322
showUncaughtError: () => boolean;
323323
patchEventTarget: (global: any, apis: any[], options?: any) => boolean[];
324324
patchOnProperties: (obj: any, properties: string[]) => void;
325+
setNativePromise: (nativePromise: any) => void;
325326
patchMethod:
326327
(target: any, name: string,
327328
patchFn: (delegate: Function, delegateName: string, name: string) =>
@@ -1318,6 +1319,9 @@ const Zone: ZoneType = (function(global: any) {
13181319
patchEventTarget: () => [],
13191320
patchOnProperties: noop,
13201321
patchMethod: () => noop,
1322+
setNativePromise: (NativePromise: any) => {
1323+
nativeMicroTaskQueuePromise = NativePromise.resolve(0);
1324+
},
13211325
};
13221326
let _currentZoneFrame: _ZoneFrame = {parent: null, zone: new Zone(null, null)};
13231327
let _currentTask: Task = null;

test/common/Promise.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {zoneSymbol} from '../../lib/common/utils';
910
import {ifEnvSupports} from '../test-util';
11+
1012
declare const global: any;
1113

1214
class MicroTaskQueueZoneSpec implements ZoneSpec {
@@ -56,6 +58,31 @@ describe(
5658
log = [];
5759
});
5860

61+
xit('should allow set es6 Promise after load ZoneAwarePromise', (done) => {
62+
const ES6Promise = require('es6-promise').Promise;
63+
const NativePromise = global[zoneSymbol('Promise')];
64+
65+
try {
66+
global['Promise'] = ES6Promise;
67+
Zone.assertZonePatched();
68+
expect(global[zoneSymbol('Promise')]).toBe(ES6Promise);
69+
const promise = Promise.resolve(0);
70+
console.log('promise', promise);
71+
promise
72+
.then(value => {
73+
expect(value).toBe(0);
74+
done();
75+
})
76+
.catch(error => {
77+
fail(error);
78+
});
79+
} finally {
80+
global['Promise'] = NativePromise;
81+
Zone.assertZonePatched();
82+
expect(global[zoneSymbol('Promise')]).toBe(NativePromise);
83+
}
84+
});
85+
5986
it('should pretend to be a native code', () => {
6087
expect(String(Promise).indexOf('[native code]') >= 0).toBe(true);
6188
});

test/common/zone.spec.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8+
import {zoneSymbol} from '../../lib/common/utils';
89

910
describe('Zone', function() {
1011
const rootZone = Zone.current;
@@ -326,17 +327,23 @@ describe('Zone', function() {
326327
Zone.assertZonePatched();
327328
});
328329

329-
it('should throw when Promise has been patched', () => {
330-
class WrongPromise {}
330+
it('should keep ZoneAwarePromise has been patched', () => {
331+
class WrongPromise {
332+
static resolve(value: any) {}
333+
334+
then() {}
335+
}
331336

332337
const ZoneAwarePromise = global.Promise;
338+
const NativePromise = (global as any)[zoneSymbol('Promise')];
333339
global.Promise = WrongPromise;
334340
try {
335341
expect(ZoneAwarePromise).toBeTruthy();
336-
expect(() => Zone.assertZonePatched()).toThrow();
342+
Zone.assertZonePatched();
343+
expect(global.Promise).toBe(ZoneAwarePromise);
337344
} finally {
338345
// restore it.
339-
global.Promise = ZoneAwarePromise;
346+
global.Promise = NativePromise;
340347
}
341348
Zone.assertZonePatched();
342349
});

0 commit comments

Comments
 (0)