I didn't use throw new ReferenceError much before, and when I am using, I found out it will stop the script:
alert("a"); //Yes
throw new ReferenceError("Error."); //Yes
alert("b"); //Nope
http://jsfiddle.net/DerekL/uKEZ4/
I just want to throw an error in the console without stopping the whole script. I tried to do this:
alert("a"); //Yes
try{
throw new ReferenceError("Error."); //Yes
}catch(e){}
alert("b"); //Yes
http://jsfiddle.net/DerekL/uKEZ4/1/
This will work, but I don't think this is the best approach. What is the best way to display an error message without stopping the script?
PS:
console.warn("Error");
won't work on IE.
This behavior is by design. Exception handling in JavaScript works just like it does in many other languages: C#, Java, Ruby, etc.
When an exception is thrown it will unwind the stack and it will skip execution of code until it is caught with a catch (where it will "resume" execution). If there is no catch, then it just skips off the end of the code entirely (script element, source file, REPL, etc). finally is also an option in cases (to "resume" execution), but there is nothing like On Error Resume Next; that's just not JavaScript.
There is nothing to change this behavior.
(I recommend just shimming IE to support console.)
Error just a simply Object.whataever you throw, they always break the exec flow.
Related
I noticed that qUnit doesn't give any notice when an exception happens in a later part of the test. For example, running this in a test():
stop();
function myfun(ed) {
console.log('resumed');
start(); //Resume qunit
ok(1,'entered qunit again');
ok(ed.getContent()== 'expected content') // < causes exception, no getContent() yet.
}
R.tinymce.onAddEditor.add(myfun)
in an inner iframe on the page will cause an exception (TypeError: ed.getContent is not a function),
but nothing in Qunit status area tells this. I see 0 failures.
(R being the inner iframe, using technique here: http://www.mattevanoff.com/2011/01/unit-testing-jquery-w-qunit/) Would I be correct in assuming this isn't the best way to go for testing sequences of UI interaction that cause certain results? Is it always better to use something like selenium, even for some mostly-javascript oriented frontend web-app tests?
As a side note, the Firefox console shows the console.log below the exception here, even though it happened first... why?
If you look into qUnit source code, there are two mechanisms handling exceptions. One is controlled by config.notrycatch setting and will wrap test setup, execution and teardown in try..catch blocks. This approach won't help much with exceptions thrown by asynchronous tests however, qUnit isn't the caller there. This is why there is an additional window.onerror handler controlled by Test.ignoreGlobalErrors setting. Both settings are false by default so that both kinds of exceptions are caught. In fact, the following code (essentially same as yours but without TinyMCE-specific parts) produces the expected results for me:
test("foo", function()
{
stop();
function myfun(ed)
{
start();
ok(1, 'entered qunit again');
throw "bar";
}
setTimeout(myfun, 1000);
});
I first see a passed tests with the message "entered qunit again" and then a failed one with the message: "uncaught exception: bar." As to why this doesn't work for you, I can see the following options:
Your qUnit copy is more than two years old, before qUnit issue 134 was fixed and a global exception handler added.
Your code is changing Test.ignoreGlobalErrors setting (unlikely).
There is an existing window.onerror handler that returns true and thus tells qUnit that the error has been handled. I checked whether TinyMCE adds one by default but it doesn't look like it does.
TinyMCE catches errors in event handlers when calling them. This is the logical thing to do when dealing with multiple callbacks, the usual approach is something like this:
for (var i = 0; i < callbacks.length; i++)
{
try
{
callbacks[i]();
}
catch (e)
{
console.error(e);
}
}
By redirecting all exceptions to console.error this makes sure that exceptions are still reported while all callbacks will be called even if one of them throws an exception. However, since the exception is handled jQuery can no longer catch it. Again, I checked whether TinyMCE implements this pattern - it doesn't look like it.
Update: Turns out there is a fifth option that I didn't think of: the exception is fired inside a frame and qUnit didn't set up its global error handler there (already because tracking frame creation is non-trivial, a new frame can be created any time). This should be easily fixed by adding the following code to the frame:
window.onerror = function()
{
if (parent.onerror)
{
// Forward the call to the parent frame
return parent.onerror.apply(parent, arguments);
}
else
return false;
}
Concerning your side-note: the console object doesn't guarantee you any specific order in which messages appear. In fact, the code console.log("foo");throw "bar"; also shows the exception first, followed by the log message. This indicates that log messages are queued and handled delayed, probably for performance reasons. But you would need to look into the implementation of the console object in Firefox to be certain - this is an implementation detail.
This may be a bad question, but I've noticed that as I'm writing coding along using mootools When I've got some code that goes through callbacks, bindings and generally isn't just a straight forward function call, if there's an error it doesn't get picked up by either Firebug or Chrome's console it just silently fails, and I'm forced to track down the error using trys and such that don't give you handy information like the line of code that's failing. It's like writing code for IE6 all you have to go on is some opaque message like 'can not read 'x' of undefined.'
I realize that the question isn't specific enough to ask 'how do I avoid this' but does anyone else run into this problem and if so how do you work around it? I'm also a little confused how an error could be picked up by a try/catch block, but not the javascript console.
EDIT:
OK, I've come up with something that reproduces the error
say you've got a function
function foo(){
var x = value.blah;
}
if I call that function like foo() I rightly get an reference error in my console. If, however, I call it like
(function(){
foo.attempt();
})()
I get no error in the console, but if I change foo to be
function foo(){
try{
var x = value.blah;
} catch(e){console.log(e)}
}
the console will log e but of course without the handle 'line: whatever' information.
I have considerable experience fiddling with errors in JavaScript. I've mostly used Chrome for building my understanding but most of it applies to Firefox and Internet Explorer as well.
I can immediately debunk your assumption about silent JavaScript errors. They don't exist, Errors always show. There might be a bug in Firefox or the Chrome's webdev, but the errors are there.
The most common way for errors not to show up is because you're catching them yourself. Perhaps prematurely.
I've figured out what I think is the best strategy for catching errors:
1. Always throw things that are Errors or inherited from Errors.
Ex: not: throw "Precondition failed" but throw new Error("Precondition failed").
This is because Errors are weird in JavaScript (I have no other word for it). If you want a stacktrace (and heaven's yes you want a stacktrace) you'll need to throw an Error (and not a string).
2. Don't use window.onerror Not much to say here. It's useless. You have no control over what get's flung to this function. It might be your code, it might be a broken plugin that a visitor uses. Also, no stacktrace.
3. Have one (global) error handler / when to catch errors
JavaScript is event driven. This has some unexpected consequences. Observe the following code:
try {
setTimeout(function () {
throw new Error("nope! :D");
}, 1);
} catch (e) {
console.log(e);
}
You will not see this error. (Firebug / console will catch it though)
This is because the inner function runs in it's own event and the try-catch statement no longer applies to it. The correct way is:
try {
setTimeout(function () {
try {
throw new Error("nope! :D");
} catch (e) {
console.log("Hell yea!", e);
}
}, 1);
} catch (e) {
console.log(e);
}
Or just make a function that wraps a function in a try-catch:
function wrap(wrap_dat_func) {
return function () {
try {
wrap_dat_func.apply(wrap_dat_func, arguments);
} catch (e) {
// send to error handler
}
}
}
Use like:
setTimeout(wrap(function () {
// etc
}), 1);
So basically whenever you generate a new event, wrap the callback in your global try catch function. So wrap call to setTimeout, setInterval all DOM related events like onclick onload ondocumentready, also AJAX calls onreadystatechanged.
How to get proper stacktraces (over events!) is another long winded explanation.
I try to simulate a problem where a script that is loaded from an external url stops execution of any more scripts on my site.
I tried to simulate such a problem by calling a function that does not exits. I can see the error in firebug but different scripts on the page are still executed.
Are there different kinds of errors in Javascripts? If yes: what kind of error stops script execution? I only need this answer for Firefox.
EDIT
This question is easy to misunderstood but Rob W got it: I need to throw an exception and that exception needs to stop further script execution.
Answer to the title: No
Answer to "Are there different kinds of errors in JavaScript**: Yes, see MDN: Error
Syntax errors will prevent a whole script block from being executed,
other errors (TypeErrors, Reference errors) will only stop the execution after the occurrence of the error.
Different <script> blocks are executed separately. You cannot prevent the second block from execution by throwing an error in the first block (Demo: http://jsfiddle.net/WJCEN/).
<script>Example: Syntax error in this script.</script>
<script>console.log('Still executed.')</script>
Also, if an error is caught using try-catch (demo: http://jsfiddle.net/WJCEN/1/), then the error will not even stop the execution a whole block.
try {throw 'Code';}catch(e){}
console.log('Still executed');
There is no general one-fit-all method to stop all code from running. For individual scripts, you can use some tricks to prevent the code from running further.
Example 1 (demo): Temporary overwrite a method
1: <script>window._alert = alert;alert=null;</script>
2: <script>alert('Some code!');confirm('Not executing');</script>
3: <script>alert=_alert;delete window._alert;alert('Done!');</script>
This method is based on the fact that script 2 expects alert to be a function. We have rewritten alert to a non-function property (script 1). Script 2 throws a TypeError, and the second block is skipped.
We restore the original values in script 3.
Example 2 (demo): Define a constant method, which cannot be overwritten.
4. <script>Object.defineProperty(window, 'test',{value:null});</script>
5. <script>var test=function(){alert('Test');};test();alert('What?');</script>
This methods relies on the Object.defineProperty method, to effectively define a constant value. In strict mode, the var test declaration would throw a TypeError: "test is read-only".
When strict mode is not enables, a TypeError will be thrown at test(): "test is not a function" (because we defined test to be constant, in script 4).
Note: The last method is not working correctly with function declarations (see bug #115452, Chrome 17)
Use
try catch finally block
It will do the trick
you can use the error object which support the following two properties:
name: The name of the error.
message: A description of the error.
for example to stop execution you can use : throw new Error("myError");
Are there different kinds of errors in Javascripts?
Besides the generic Error constructor, there are six other core errors in JavaScript:
see here details on these errors.
Stop the execution with
throw new Error('stopIt');
This will also do the trick:
throw 'Stop It!';
I have
function Student(){
var that=this;
that.SaveChanges=function(){
//.....
}
function init(){
that.SaveChanges1();
}
init();
}
<script type="text/javascript">
$(document).ready(function () {
var student=new Student();
});
</script>
With jquery-1.4.4.min.js, I could not save changes, because I made error, but rest of the application work.
With jquery-1.7.1.min.js I get error Object # has no method 'SaveChanges1' and rest of the application does not work.
OR
that.SaveChanges1 is not a function
[Break On This Error]
(77 out of range 4)
What should I do to work like with jquery-1.4.4.min.js?
I think you should try NOT to make errors in your javascript... It's good that it blows up, at least it warns you that something doesn't work! Perhaps you should try running some javascript or selenium tests and perhaps a jslint check to make sure that you don't break any of your javascript functionality!
If you want to ignore your errors in some parts of your program, you can do so by using exception handling. But, you cannot just blindly ignore all errors because when a portion of your script gets an error, that portion of the script has to stop executing as there is no orderly way to continue execution after an error. The javascript interpreter doesn't know which types of errors are harmless and which types mess up the whole script.
To catch an exception in one part of the script and continue executing other parts, you can add your own exception handling like this:
try {
// your code here that might cause a run-time error
} catch(e) {
// might want to put some debugging code here so you know that an error was thrown
}
// more code here that will execute even if the previous code threw an error
Note: you can use exception handling for run-time execution errors. You cannot use it for syntax errors that prevent compilation of the javascript code because when that happens, the interpreter can't even understand your code.
function testFun() {
onerror = function() { log("caught the error"); return true; };
setTimeout(function() { throw "bad bad bad"; }, 300);
};
This is sample, code, but it demonstrates a problem.
If I run this in FF, or IE7, it prints the sensible "caught the error" message (assume a reasonable 'log' function).
However if I debug the code in VS2008, the debugger stops on the throw with the message: 'Microsoft JScript runtime error: Exception thrown and not caught'. If I say 'continue' or 'ignore', the log message is not produced.
This is a problem since the real code I am working with is much larger than this, and I'll occasionally want to, you know, debug stuff. So two questions:
Any know why and can I modify this behaviour with some flag I don't know about?
Am I doing what I think I'm doing (setting the global 'onerror' handler) in this code? If not, what is the appropriate pattern for catching this type of error?
Note: There is no difference wrt this problem if I use window.onerror instead.
According to this defining a global onerror function doesn't work in IE. They were probably talking about IE6 or earlier, so maybe MS have fixed it for IE7 - however I wouldn't expect this to just automatically flow through to the VS debugger.
At any rate, try using window.onerror = function rather than just onerror.
If that doesn't work, you'll have to use a try/catch block inside your timer function I guess.
PS: Get firefox and use firebug. the debugger (and everything else) is much better and nicer to use than the VS debugging