I'm writing quite a bit of code in Prototype.js which returns null if a DOM-id wasn't found.
$("someId").show();
If someId doesn't exist, a method will be called on null, which halts the entire program, in effect disabling all JS effects after the error. I could just check for null before executing such a statement, but this is getting tiring.
I would like to catch an exception but I'm not sure which one its is. MDC lists the following ECMA Script error types, but on first glance none of them seem to be what I want:
* Error
* EvalError
* RangeError
* ReferenceError
* SyntaxError
* TypeError
* URIError
* DOMException
* EventException
* RangeException
Also, do browsers have a unified way of dealing with a method call on null?
I don't believe there's unity to be found. Chrome throws a TypeError, but IE throws an Error, so you would probably have to catch everything and make severe assumptions. Better to check for null first.
var element = $('someId');
if (element) {
element.show();
// whatever else...
}
If element.show() is the only thing you need it for, then it can obviously be written a lot shorter, but in most cases that would be appropriate.
The correct way to handle this is to check for null before doing something with an object. There are several shorthand ways to do this, the shortest is (as Alex K) wrote
$("someId") && $("someId").show();
but this seems to me to be harder to read.
To answer your question directly you can do
try { $('someId').show(); } catch (e) {}
but this seems amateurish. You should program explicitly because later on someone else won't know why you wrote that odd code. The first example is slightly opaque but at least contains the null test first, and doesn't hide errors in the show() method.
Incidentally, if you were using JQuery instead of Prototype, this code would work without error even if there is no object with id 'someId':
$('#someId').show()
That's because the $() function in JQuery returns a collection which may be empty but is never null.
If your going to chain .show() on $("someId") then check its result first.
if ($("someId"))
$("someId").show();
or
$("someId") && $("someId").show();
or
if (someVar = $("someId"))
someVar.show();
If for some reason you really need to identify them you could wrap $() and throw a custom exception:
function NullReferenceException(id) {this.id = id}
function $my(id) {
var el = $(id);
if (!el)
throw new NullReferenceException(id);
return el
}
try {
$my("iDontExistId").show();
} catch (e) {
if (e instanceof NullReferenceException)
alert(e.id + " doesn't exist");
}
Just ignore which exception it is...
try
{
null.hey()
}
catch(e)
{
//handle it here
}
Related
I'm guessing the answer to my question is no, but since I don't know enough about how Error.prototype works I figured it was worth asking: is there any way to change the error messages from the errors in Javascript?
For instance, if I get an error:
TypeError: (intermediate value) is not iterable
is there any way to change things such that I instead get:
TypeError: You expected an array but it wasn't an array dummy!
I thought about using a global error handler and then rethrowing them, but that would only work for uncaught errors. Is there any Error.prototype method I can change (or any other way) to do this?
Not at all important, just curious.
EDIT: Just to clarify two points:
1) I understand how try/catch works, but what I'm asking about is whether there is a way to control the messages generated before the error is thrown/caught (presumably by overwriting a method of Error.prototype).
2) An answer of "no there is no way to do this, all generating of JS error messages is handled internally and the JS code has no way to control it" would be perfectly legitimate (... if that's the case).
You have to override the TypeError class, not one of these methods.
const overridableMessages = [{
search: 'TypeError: (intermediate value) is not iterable',
replace: 'TypeError: You expected an array but it wasn\'t an array dummy!'
}]
class TypeError extends window.TypeError {
constructor (message) {
super(message)
overridableMessages.forEach((overridableMessage) => {
if (this.message === overridableMessage.search) {
this.message = overridableMessage.replace
}
})
}
}
window.TypeError = TypeError
window.onerror = function(msg, url, linenumber) {alert('Error : '+msg+'\nURL: '+url+'\nLine Number: '+linenumber);return true;}
// general error handler
Also:
try {
}
catch(err) {
alert(err); // here put your case with your messages.
}
// routine error handler
HIH,
I hate to answer my own question, but I found this line on the MDN which seems to pretty clearly answer things:
The global Error object contains no methods of its own, however, it does inherit some methods through the prototype chain.
Since the only methods it gets through the prototype chain are toString and toSource (neither of which controls an error's generated message), it appears (unless I'm missing some other mechanism that isn't Error.prototype-related) that there is no way to accomplish what I asked.
I am trying to build a catch try to execute some javascript code. NO JQUERY I want to identify if a div id ('test') exists and if it doesn't don't execute the code. How would I do this? I know the structure of a try catch is
try{
}
catch(e){
}
use try-catch as less as possible: just check whether or not the DOM element exists:
if (document.getElementById('test')!=null) {
// element (div) with id 'test' exists
}
else {
// it doesn't
}
I would make things simpler and use if instead of try-catch. try-catch is designed for exceptional situations, when you really don't know what to do throw an error. Throwing an error causes the whole code block to terminate it's execution.
I would do like this:
var divId = 'test';
if (document.getElementById(divId)) {
alert('exists');
} else {
alert('does not exist');
}
There is no need to check document.getElementById() result on null (in all modern browsers null is returned when no element is found). In most JavaScript projects developers skip typing !== null since null is treated as false and DOM object is treated as true, so programmers avoid typing obvious things.
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.
UPDATE
[Rewriting question to focus on the problem I am trying to understand.]
Is there a means in JavaScript to throw Exceptions that notify the line number where the problem occurs? Similar to C#'s debugger, if an error is thrown on line 50 then I will be taken to line 50.
For example, according to MDN EvalError represents an error with eval(). So, let's say I have a function that uses eval(). I want to use a specific error that is representative of the problem at hand, EvalError:
//As written here the error implies there is a problem on this line. See Firebug console window
var evalErra = new EvalError('required element missing from evaluation');
var stringFunc = "a=2;y=3;document.write(x*y);";
EvalString(stringFunc);
function EvalString(stringObject) {
//Some arbitrary check, for arguments sake let's say checking for 'x' makes this eval() valid.
if(stringObject.indexOf('x') !== -1) {
throw evalErra;
//throw 'required element missing from evaluation';//This way offers no line number
}
eval(stringFunc);//The problem really lies in the context of this function.
}
If I'm going about this all wrong, then please tell me how I should approach these kinds of issues.
When you throw an error, execution of the current code will stop and JS will work its way back up the execution tree until it finds a catch () which handles the particular type of error being thrown, or gets all the way up to the top of the tree, causing an "unhandled exception" error: You threw an error, and nothing caught it, and now someone's window got broken.
try {
if (true) {
throw 'yup'
}
} catch (e) { // catches all errors
... handle the error
}
When doing error handling you want to do the following
throw new Error("message");
Then if you ever handle this error look at err.stack (firefox/opera/chrome) or err.line (Safari) or err.IE_Y_U_NO_SHOW_ME_ERROR_LINE_NUMBER (IE) to find the line number.
If you want you can subclass Error.
is it possible to register an error or exception handler/function that will be executed when a javascript error or exception occurs? I just feel wrapping all codes in try/catch block seems very tedious and inefficient.
window.onerror = function (msg, file, line) {
// handle error here
}
Supported by:
Chrome 13+
Firefox 6.0+
Internet Explorer 5.5+
Opera 11.60+
Safari 5.1+
Andy E's answer (+1) tells you how to do it.
That said, JavaScript isn't really meant to have caught execeptions in the same sense that, say, Java does. If your code is throwing exceptions, pull up a console and use the debugger to fix them. JS exceptions are slow, and really not meant to be used for flow control. A method won't throw an exception unless there's a serious problem — and it's usually a programming error.
Here's an alternative answer than the window.onerror solution. This isn't something I've used in production, but is something that I just like because of the flexibility (i.e. you could use it to debug things like timing how long a method took or something).
Whilst you could probably pass window into it (don't quote me on that, and don't think it's a good idea) it does work if you have all your methods in an object:
(function(obj) {
for (var name in obj) {
if (typeof(obj[name]) == 'function') {
currentMethod = obj[name];
obj[name] = function() {
try {
currentMethod();
}
catch (e) {
alert('Exception Handler: ' + e);
}
};
}
}
}(myObject));
Here's it working: http://jsfiddle.net/jonathon/kpYnW/
Basically, it goes through each property in your object, finds the ones that are functions and wraps them in a try/catch (or whatever else you want).
Whether or not it's efficient is a different matter - I've just found it a very useful technique for debugging. Unfortunately I can't remember the original place I read it but if anyone knows, please add as a comment.