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

Commit

Permalink
fix(error): remove throw in Error constructor to improve performance …
Browse files Browse the repository at this point in the history
…in IE11 (#704)

* fix(error): remove throw in Error constructor to improve performance in IE

* fix(error): fix #698, don not generate long stack trace when Error.stackTraceLimit = 0, add null check
  • Loading branch information
JiaLiPassion authored and mhevery committed Apr 10, 2017
1 parent 967a991 commit 88d1a49
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 26 deletions.
45 changes: 30 additions & 15 deletions lib/zone-spec/long-stack-trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function addErrorStack(lines: string[], error: Error): void {
}

function renderLongStackTrace(frames: LongStackTrace[], stack: string): string {
const longTrace: string[] = [stack.trim()];
const longTrace: string[] = [stack ? stack.trim() : ''];

if (frames) {
let timestamp = new Date().getTime();
Expand Down Expand Up @@ -97,26 +97,38 @@ function renderLongStackTrace(frames: LongStackTrace[], stack: string): string {

onScheduleTask: function(
parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task): any {
const currentTask = Zone.currentTask;
let trace = currentTask && currentTask.data && (currentTask.data as any)[creationTrace] || [];
trace = [new LongStackTrace()].concat(trace);
if (trace.length > this.longStackTraceLimit) {
trace.length = this.longStackTraceLimit;
if (Error.stackTraceLimit > 0) {
// if Error.stackTraceLimit is 0, means stack trace
// is disabled, so we don't need to generate long stack trace
// this will improve performance in some test(some test will
// set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698
const currentTask = Zone.currentTask;
let trace = currentTask && currentTask.data && (currentTask.data as any)[creationTrace] || [];
trace = [new LongStackTrace()].concat(trace);
if (trace.length > this.longStackTraceLimit) {
trace.length = this.longStackTraceLimit;
}
if (!task.data) task.data = {};
(task.data as any)[creationTrace] = trace;
}
if (!task.data) task.data = {};
(task.data as any)[creationTrace] = trace;
return parentZoneDelegate.scheduleTask(targetZone, task);
},

onHandleError: function(
parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: any): boolean {
const parentTask = Zone.currentTask || error.task;
if (error instanceof Error && parentTask) {
const longStack =
renderLongStackTrace(parentTask.data && parentTask.data[creationTrace], error.stack);
try {
error.stack = (error as any).longStack = longStack;
} catch (err) {
if (Error.stackTraceLimit > 0) {
// if Error.stackTraceLimit is 0, means stack trace
// is disabled, so we don't need to generate long stack trace
// this will improve performance in some test(some test will
// set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698
const parentTask = Zone.currentTask || error.task;
if (error instanceof Error && parentTask) {
const longStack =
renderLongStackTrace(parentTask.data && parentTask.data[creationTrace], error.stack);
try {
error.stack = (error as any).longStack = longStack;
} catch (err) {
}
}
}
return parentZoneDelegate.handleError(targetZone, error);
Expand All @@ -131,6 +143,9 @@ function captureStackTraces(stackTraces: string[][], count: number): void {
}

function computeIgnoreFrames() {
if (Error.stackTraceLimit <= 0) {
return;
}
const frames: string[][] = [];
captureStackTraces(frames, 2);
const frames1 = frames[0];
Expand Down
10 changes: 0 additions & 10 deletions lib/zone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1630,16 +1630,6 @@ const Zone: ZoneType = (function(global: any) {
function ZoneAwareError(): Error {
// We always have to return native error otherwise the browser console will not work.
let error: Error = NativeError.apply(this, arguments);
if (!error.stack) {
// in IE, the error.stack will be undefined
// when error was constructed, it will only
// be available when throw
try {
throw error;
} catch (err) {
error = err;
}
}
// Save original stack trace
const originalStack = (error as any)['originalStack'] = error.stack;

Expand Down
25 changes: 24 additions & 1 deletion test/zone-spec/long-stack-trace-zone.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ describe('longStackTraceZone', function() {
setTimeout(function() {
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('Hello Promise'));
try {
throw new Error('Hello Promise');
} catch (err) {
reject(err);
}
}, 0);
});
promise.catch(function(error) {
Expand All @@ -116,4 +120,23 @@ describe('longStackTraceZone', function() {
}, 0);
});
});

it('should not produce long stack traces if Error.stackTraceLimit = 0', function(done) {
const originalStackTraceLimit = Error.stackTraceLimit;
lstz.run(function() {
setTimeout(function() {
setTimeout(function() {
setTimeout(function() {
if (log[0].stack) {
expectElapsed(log[0].stack, 1);
}
Error.stackTraceLimit = originalStackTraceLimit;
done();
}, 0);
Error.stackTraceLimit = 0;
throw new Error('Hello');
}, 0);
}, 0);
});
});
});

0 comments on commit 88d1a49

Please sign in to comment.