fix(zone.js): disable wrap uncaught promise rejection should handle primitive value (#38476)
Close #38334. zone.js provides a flag DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION to let zone.js throw the original error instead of wrap it when uncaught promise rejection found. But the rejection value could be anything includes primitive value such as number. In that case, we should not attach any additional properties to the value. PR Close #38476
This commit is contained in:
parent
f979914d4e
commit
19d543f71e
|
@ -1,5 +1,3 @@
|
|||
import {patchMethod} from './utils';
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
|
@ -7,6 +5,8 @@ import {patchMethod} from './utils';
|
|||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {patchMethod} from './utils';
|
||||
|
||||
Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
||||
const ObjectDefineProperty = Object.defineProperty;
|
||||
|
@ -48,6 +48,9 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
|
|||
const uncaughtPromiseError: UncaughtPromiseError = _uncaughtPromiseErrors.shift()!;
|
||||
try {
|
||||
uncaughtPromiseError.zone.runGuarded(() => {
|
||||
if (uncaughtPromiseError.throwOriginal) {
|
||||
throw uncaughtPromiseError.rejection;
|
||||
}
|
||||
throw uncaughtPromiseError;
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -191,20 +194,20 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
|
|||
if (queue.length == 0 && state == REJECTED) {
|
||||
(promise as any)[symbolState] = REJECTED_NO_CATCH;
|
||||
let uncaughtPromiseError = value;
|
||||
if (!isDisableWrappingUncaughtPromiseRejection) {
|
||||
try {
|
||||
// Here we throws a new Error to print more readable error log
|
||||
// and if the value is not an error, zone.js builds an `Error`
|
||||
// Object here to attach the stack information.
|
||||
throw new Error(
|
||||
'Uncaught (in promise): ' + readableObjectToString(value) +
|
||||
(value && value.stack ? '\n' + value.stack : ''));
|
||||
} catch (err) {
|
||||
uncaughtPromiseError = err;
|
||||
}
|
||||
if (isDisableWrappingUncaughtPromiseRejection) {
|
||||
// If disable wrapping uncaught promise reject
|
||||
// and the rejected value is an Error object,
|
||||
// use the value instead of wrapping it.
|
||||
try {
|
||||
// Here we throws a new Error to print more readable error log
|
||||
// and if the value is not an error, zone.js builds an `Error`
|
||||
// Object here to attach the stack information.
|
||||
throw new Error(
|
||||
'Uncaught (in promise): ' + readableObjectToString(value) +
|
||||
(value && value.stack ? '\n' + value.stack : ''));
|
||||
} catch (err) {
|
||||
uncaughtPromiseError = err;
|
||||
}
|
||||
uncaughtPromiseError.throwOriginal = true;
|
||||
}
|
||||
uncaughtPromiseError.rejection = value;
|
||||
uncaughtPromiseError.promise = promise;
|
||||
|
|
|
@ -383,6 +383,7 @@ interface UncaughtPromiseError extends Error {
|
|||
task: Task;
|
||||
promise: Promise<any>;
|
||||
rejection: any;
|
||||
throwOriginal?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,9 +42,9 @@ describe('disable wrap uncaught promise rejection', () => {
|
|||
setTimeout((): any => null);
|
||||
setTimeout(() => {
|
||||
expect(promiseError).toBe(error);
|
||||
expect((promiseError as any)['rejection']).toBe(error);
|
||||
expect((promiseError as any)['zone']).toBe(zone);
|
||||
expect((promiseError as any)['task']).toBe(task);
|
||||
expect((promiseError as any)['rejection']).toBe(undefined);
|
||||
expect((promiseError as any)['zone']).toBe(undefined);
|
||||
expect((promiseError as any)['task']).toBe(undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -76,4 +76,27 @@ describe('disable wrap uncaught promise rejection', () => {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should print original information when a primitive value is used for rejection', (done) => {
|
||||
let promiseError: number|null = null;
|
||||
Zone.current
|
||||
.fork({
|
||||
name: 'promise-error',
|
||||
onHandleError: (delegate: ZoneDelegate, current: Zone, target: Zone, error: any):
|
||||
boolean => {
|
||||
promiseError = error;
|
||||
delegate.handleError(target, error);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.run(() => {
|
||||
Promise.reject(42);
|
||||
expect(promiseError).toBe(null);
|
||||
});
|
||||
setTimeout((): any => null);
|
||||
setTimeout(() => {
|
||||
expect(promiseError).toBe(42);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue