-
Notifications
You must be signed in to change notification settings - Fork 408
Fix #546, #554, #555, the error should keep prototype chain and can be called without new #559
Conversation
…otype chain and can be called without new
|
||
// Copy the prototype so that instanceof operator works as expected | ||
ZoneAwareError.prototype = NativeError.prototype; | ||
ZoneAwareError.prototype = Object.create(NativeError.prototype); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is Object.create
necessary here? What is wrong with having it the way it was before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just want to create a new object to let ZoneAwareError.prototype be different with NativeError's, so in the future, if someday modify ZoneAwareError's prototype will not impact NativeError's, for this issue #546, we don't need to use Object.create
} | ||
return error; | ||
} | ||
return (this && this !== global) ? this : error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that sometimes we return this
and sometimes errror
concerns me. We have two seperate code path and I fear that things will only work in one or the other code path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is a little risky code, I will modify it.
@@ -1318,13 +1318,24 @@ const Zone: ZoneType = (function(global: any) { | |||
function ZoneAwareError() { | |||
// Create an Error. | |||
let error: Error = NativeError.apply(this, arguments); | |||
|
|||
if (this && this !== global) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a better strategy would be to always assume that we were called without the new
operator, that way we don't have to decide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I understand your concern, you are right. I will change it.
@mhevery , Thank you for your review, I'll consider it again and reply to you soon. |
found another problem, In typescript 2.0.8, the class extends will be compiled into var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var MyError = (function (_super) {
__extends(MyError, _super);
function MyError() {
_super.apply(this, arguments);
}
return MyError;
}(Error)); This is not correct, In typescript 2.1.4 , it will be compiled into var MyError = (function (_super) {
__extends(MyError, _super);
function MyError() {
return _super.apply(this, arguments) || this;
}
return MyError;
}(Error)); This is the correct one. |
@mhevery , I have changed my PR, please review it is correct or not, Thanks a lot. |
@@ -69,7 +69,7 @@ | |||
"ts-loader": "^0.6.0", | |||
"tslint": "^3.15.1", | |||
"tslint-eslint-rules": "^3.1.0", | |||
"typescript": "^2.0.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not upgrade to TS 2.1.4 since we have to make sure that the generated .d.ts
is compatible with angular which is on alder version on TS. The easiest is to wait until angular is ready.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I see, I will rollback the typescript version.
// and not global (non-strict mode call Error()) | ||
// and it is an error not an unrelated object | ||
if (this && this !== global && this instanceof Error) { | ||
error = setPrototypeOf(error, getPrototypeOf(this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling setProtypeOf
will make this object slow. Not sure if that is a problem since it is a Error object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for pointing out this one, I didn't realize that setPrototypeOf will make javascript engine optimization become slow. how about change the code above to
// if this is valid, means not undefined
// and not global (non-strict mode call Error())
// and it is an error not an unrelated object
if (this && this !== global && this instanceof Error) {
assignAll(this, error);
return this;
}
-Pro: don't use setPrototypeOf
-Con:if/else will return different object
I just make a new commit to describe it, please review.
@@ -1387,8 +1387,8 @@ const Zone: ZoneType = (function(global: any) { | |||
// if this is valid, means not undefined | |||
// and not global (non-strict mode call Error()) | |||
// and it is an error not an unrelated object | |||
if (this && this !== global && this instanceof Error | |||
&& Object.getPrototypeOf(this) !== NativeError.prototype && assignAll(this, error)) { | |||
if (this && this !== global && this instanceof Error && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about this some more, and I think the best way to do this would be to place this guard at the top of the function
if (! this instanceof ZoneAwareError) {
return ZoneAwareError.apply(Object.create(ZoneAwareError), arguments);
}
This way we force the new
and only have one code path. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review, in my understanding, your code will guarantee that 'this' is a valid ZoneAwareError, and we can set all properties from error to this and then return this. Is my understanding correct?
I have modified the PR based on your idea, please review. Thank you.
Thanks for all of your hard work. |
With the commit #547, the #546, error prototype issue was fixed, but a bigger issue occurs, that
Error object can be created with direct call.
let error = Error('message');
And the #547 PR will break it, cause a lot of errors, such as #554, #555
Sorry for the buggy commit in #547.
In this new PR, I checked the this exists or not and checked the this is global or not (non strict mode). So it should fix both #546 and #554, #555.
Please review, Thank you.