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

Commit 956c729

Browse files
JiaLiPassionmhevery
authored andcommitted
fix(promise): can set native promise after loading zone.js (#899)
* fix(promise): can set native promise after loading zone.js * disable SL_IOS9
1 parent e999593 commit 956c729

9 files changed

+106
-23
lines changed

Diff for: karma-base.conf.js

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = function (config) {
1616
{pattern: 'node_modules/rxjs/**/**/*.js', included: false, watched: false },
1717
{pattern: 'node_modules/rxjs/**/**/*.js.map', included: false, watched: false },
1818
{pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
19+
{pattern: 'node_modules/es6-promise/**/*.js', included: false, watched: false },
1920
{pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },
2021
{pattern: 'test/assets/**/*.*', watched: true, served: true, included: false},
2122
{pattern: 'build/**/*.js.map', watched: true, served: true, included: false},

Diff for: karma-dist-sauce-jasmine.conf.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88

99
module.exports = function (config) {
1010
require('./karma-dist-jasmine.conf.js')(config);
11-
require('./sauce.conf')(config);
11+
require('./sauce.conf')(config, ['SL_IOS9']);
1212
};

Diff for: lib/common/promise.ts

+38
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');

Diff for: lib/zone.ts

+4
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;

Diff for: sauce.conf.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// Sauce configuration
22

3-
module.exports = function (config) {
3+
module.exports = function (config, ignoredLaunchers) {
44
// The WS server is not available with Sauce
55
config.files.unshift('test/saucelabs.js');
66

7-
var customLaunchers = {
7+
var basicLaunchers = {
88
'SL_CHROME': {
99
base: 'SauceLabs',
1010
browserName: 'chrome',
@@ -153,6 +153,17 @@ module.exports = function (config) {
153153
}
154154
};
155155

156+
var customLaunchers = {};
157+
if (!ignoredLaunchers) {
158+
customLaunchers = basicLaunchers;
159+
} else {
160+
Object.keys(basicLaunchers).forEach(function(key) {
161+
if (ignoredLaunchers.filter(function(ignore) {return ignore === key;}).length === 0) {
162+
customLaunchers[key] = basicLaunchers[key];
163+
}
164+
});
165+
}
166+
156167
config.set({
157168
captureTimeout: 120000,
158169
browserNoActivityTimeout: 240000,

Diff for: test/common/Promise.spec.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {isNode} from '../../lib/common/utils';
9+
import {isNode, zoneSymbol} from '../../lib/common/utils';
1010
import {ifEnvSupports} from '../test-util';
1111

1212
declare const global: any;
@@ -58,6 +58,31 @@ describe(
5858
log = [];
5959
});
6060

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+
6186
it('should pretend to be a native code', () => {
6287
expect(String(Promise).indexOf('[native code]') >= 0).toBe(true);
6388
});

Diff for: test/common/zone.spec.ts

+11-4
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
});

Diff for: test/main.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ __karma__.loaded = function() {};
1616
(window as any).global = window;
1717
System.config({
1818
defaultJSExtensions: true,
19-
map: {'rxjs': 'base/node_modules/rxjs'},
19+
map: {
20+
'rxjs': 'base/node_modules/rxjs',
21+
'es6-promise': 'base/node_modules/es6-promise/dist/es6-promise'
22+
},
2023
});
2124

2225
let browserPatchedPromise: any = null;
@@ -43,4 +46,4 @@ browserPatchedPromise.then(() => {
4346
console.error(error.stack || error);
4447
});
4548
});
46-
});
49+
});

Diff for: test/rxjs/rxjs.Observable.combine.spec.ts

+7-13
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,11 @@ describe('Observable.combine', () => {
5151
const constructorZone1: Zone = Zone.current.fork({name: 'Constructor Zone1'});
5252
const subscriptionZone: Zone = Zone.current.fork({name: 'Subscription Zone'});
5353
observable1 = constructorZone1.run(() => {
54-
const source = Rx.Observable.interval(10);
55-
const highOrder = source
56-
.map((src: any) => {
57-
expect(Zone.current.name).toEqual(constructorZone1.name);
58-
return Rx.Observable.interval(50).take(3);
59-
})
60-
.take(2);
54+
const source = Rx.Observable.of(1, 2, 3);
55+
const highOrder = source.map((src: any) => {
56+
expect(Zone.current.name).toEqual(constructorZone1.name);
57+
return Rx.Observable.of(src);
58+
});
6159
return highOrder.combineAll((x: any, y: any) => {
6260
expect(Zone.current.name).toEqual(constructorZone1.name);
6361
return {x: x, y: y};
@@ -76,14 +74,10 @@ describe('Observable.combine', () => {
7674
() => {
7775
log.push('completed');
7876
expect(Zone.current.name).toEqual(subscriptionZone.name);
79-
expect(log).toEqual([
80-
{x: 0, y: 0}, {x: 1, y: 0}, {x: 1, y: 1}, {x: 2, y: 1}, {x: 2, y: 2}, 'completed'
81-
]);
77+
expect(log).toEqual([{x: 1, y: 2}, 'completed']);
8278
done();
8379
});
8480
});
85-
86-
expect(log).toEqual([]);
8781
}, Zone.root));
8882

8983
it('combineLatest func callback should run in the correct zone', () => {
@@ -141,4 +135,4 @@ describe('Observable.combine', () => {
141135

142136
expect(log).toEqual([7, 8, 9, 'completed']);
143137
});
144-
});
138+
});

0 commit comments

Comments
 (0)