It seems that pas2js does not handle "Exception" as the base class of all Exceptions. This way, the regular Delphi style error handling like this will fail in case the actual exception is not of class ERESTRequestError:
Except
On E:ERESTRequestError do
Begin
// Handle specific exception class
End;
On E:Exception do
Begin
// Handle all other exception classes
End
End
The "On E:Exception" branch will never be reached for errors thrown e.g. by javascript, like e.g. a "Type Error". And even worse: Although there is an Application error handler installed like this
Application.OnError := MyErrorHandler;
also MyErrorHandler will not catch the error. Instead, the rtl will take care of the exception and handle it in the way defined by Application.ErrorType.
I managed to help myself out of this by catching the error in a generic "Else" branch. The pitfall here is that in the "Else" branch there is no access to the exception object, and to make it even worse, pas2js does not offer acces to the Delphi global ExceptObject. So, where to get the Exception object from? I helped myself with this:
Var
JSE : Exception;
...
...
Except
On E:ERESTRequestError do
Begin
// Handle specific exception class
End
Else
// Catch all other exceptions
Begin
// Instantiate (not raise) a dummy Delphi exception object
JSE := Exception.Create('');
ASM
// Attach the javascript error object in $e to the exception
// object as well as the error message
JSE.FJSError = $e;
JSE.fMessage = $e.message;
END
// You now have a "regular" Delphi exception in JSE
// Handle the JSE exception ...
End
End
End
While this works for me for my further evaluation of the Web Core product, I would like to know if I can savely go with this approach or if I did anything "evil" here that may kick back some time later.
We'll check this with the pas2js team
Here is the answer for you from Michael Van Canneyt from the pas2js team:
It is correct that not all exceptions descend from Exception.
All browser exceptions normally descend from TJSError ("Error" in Javascript).
But even this does not have to be the case, you can raise any object as an exception in Javascript - and a string is also an object.
But the same is true in Delphi: You can perfectly raise an exception with TObject. That all exceptions are descendents of Exception is a convention.
(simply one that all programmers adhere to)
See the following demo application:
uses sysutils;
{$APPTYPE Console}
type
TMyError = Class(TObject)
FErrorCode : Integer;
constructor Create(aErrorCode : Integer);
property ErrorCode : Integer Read FErrorCode;
end;
constructor TMyError.Create(aErrorCode : Integer); begin
FErrorCode:=aErrorCode;
end;
begin
try
raise TMyError.Create(aErrorCode)
except
on E : Exception do
Writeln('Caught exception : ',E.MEssage);
end;
Readln;
end.
When run, the exception is not caught:
$ ./raiseobj.exe
Exception TMyError in module raiseobj.exe at 0001F5BA.
Because TMyError is not a descendent of Exception...
The situation in Pas2JS is not different, there are simply a lot of exceptions that are not pascal descendents of "Exception".
Now, the good news is that
On JE : TJSError do
begin
end;
works as one would expect, i.e. JavaScript exceptions will be caught and the exception object is available.
Thank you very much for this comprehensive explanation and presenting a solution! It comes absolutely clear when you dive further into the innards of pas2js and the speifics of javascript. It's just that TMS in their product presentations are somehow pretending that using Web Core is nearly identical to writing Delphi code. At least that was my assumption when I started the product evaluation. But, it is not! There are a lot of differences and many pitfalls. The problem with the different sets of sources and unidentical interfaces is also not really helpfull...(see my other post some minutes ago).
Unfortunately, not working here:
Try
Raise TJSError.New('Trallala');
Except
On JE : TJSError do
Begin
// Not going here
End;
On E:Exception do
Begin
// Not going here
End;
Else
Begin
// Only going here
End;
And btw TJSError is missing in unit JS of Component Library Source, but it is in unit JS of Core source...
Please do not mix JavaScript exceptions with Pascal exceptions. These are two different things.
Sticking to Pascal exceptions, this all works as expected:
type
MyException = class(Exception);
var
i: integer;
begin
try
i := random(10);
if i > 5 then
raise Exception.Create('Pascal Exception')
else
raise MyException.Create('Pascal MyException');
except
on e: MyException do
begin
console.log('got MyException',i);
end;
on e: Exception do
begin
console.log('got Exception',i);
end;
end;
end;
The topic was how to catch JS errors, as they are not descending from Exception. Michael Van Canneyt provided a solution On JE : TJSError do
. Did you read that? I tested this solution and it failed.
I will ask follow-up from Michael.
Hello, this is Michael.
This was a known bug: the detection of an external class failed in
Except
On E is X do
statements. This has been solved in trunk some time ago, and will be
included in pas2js 1.4.32. (Scheduled to be released this week)
If memory serves well, as a workaround you should be able to do the following:
On E : TJSObject do
begin
if E is TJSError then
begin
end;
end;
Hello Michael,
thank you for tying to help!
I tried:
On E : TJSObject do
begin
if E is TJSError then
and pas2js gives me the error "Types are not related: TJSObject and class TJSError"
To help myself I currently do this:
Var
JSE : Exception;
...
Except
On E:ERESTRequestError do
Begin
// Handle specific exception class
End
Else
// Catch all other exceptions
Begin
// Instantiate (not raise) a dummy Delphi exception object
JSE := Exception.Create('');
ASM
// Attach the javascript error object in $e to the exception
// object as well as the error message
JSE.FJSError = $e;
JSE.fMessage = $e.message;
END
// You now have a "regular" Delphi exception in JSE
// Handle the JSE exception ...
End
End
End
I can live with that until TMS releases the fix, but I just wanted to know if I'm doing anything "evil" here that potentially kicks back later.
your solution is OK.
FYI: 1.4.32 has just been released, so you can expect the fix soon.