I would like to know the best and easiest way to implement exception handling in Javascript. I'm looking for a "one point" solution. I've got lot of functions and wouldn't want to go around and implement try-catch.
I feel window.onerror would be a better approach, since I just have to implement this in one place and any exceptions that occurs in any of the functions, I would be able to handle it using window.onerror. However, this seems to be supported only in IE. Is there any similar way that I can use so that it supports all major standard browsers.
Thanks in advance.
Using try..catch block
try..catch block in JavaScript is very much similar to the regular C# try..catch block. The suspected code will be put in try block and all exceptions which will occur in the try block will be caught in catch block.
window.onload = function()
{
try
{
var x = 90;
var value = x / y;
}
catch(err)
{
document.write(err.name + ": " + err.message + "<br/>");
}
}
Output:
TypeError: 'y' is undefined
In catch you will get the object containing type and description of the exception. More over you can also use finally block in the same way as you use in C#.
window.onload = function()
{
try
{
var x = 90;
var value = x / y;
}
catch(err)
{
document.write(err.name + ": " + err.message + "<br/>");
}
finally
{
alert('This is finally block');
}
}
Using onerror event
onerror event will be raised each time there is any error while performing a action in the document. This like on place exception handling similar to Application_Error in ASP.NET. Here is sample code which demonstrate this:
window.onload = function()
{
var x = 90;
var value = x / y;
}
window.onerror = function(errorMeaage, fileName, lineNumber)
{
document.write('Error: ' + errorMeaage);
}
Using jQuery Solution
It is similar to using onerror but with jQuery syntax. The syntax is:
$(window).error(
function(errorMeaage, fileName, lineNumber)
{
// handle error here
}
);
Excerpt from JavaScript Exception Handling Techniques
If there are just a handful of functions calling each other, I'd do something like this.
try{
main();
}
catch(e){
//error
}
Where main() would be the function that calls everything else; a la, the entry point within your script. Although, this doesn't leave you with a lot of flexibility in the code called below. So consider making different "levels" of functions, where each call to them is wrapped in a try...catch block where you can handle them appropriately. ie.
function a(){}
function b(){}
function main(){
//call a, catch any errors
try{
a();
}
catch(e){}
//call b, catch any errors
try{
b();
}
catch(e){}
//and so on...
}
main();
Related
Is there any reason to use if to check if method exists, before calling await
if (someObject.save){
await someObject.save();
}
rather than using nullish coallescence diectly with await
await someObject.save?.();
Is second code a safe alternative to the former?
Is second code a safe alternative to the former?
Yes. But maybe not for the reason one might expect.
The two pieces of code are equivalent in terms of the check made:
const obj = {
foo() { console.log("method called"); },
bar: 42
};
if (obj.foo) {
console.log("obj has foo");
obj.foo(); //works
}
console.log("using optional chaining");
obj.foo?.(); //works
if (obj.bar) {
console.log("obj has bar");
try {
obj.bar(); //error
} catch (err) {
console.log("bar cannot be called");
}
}
console.log("using optional chaining");
try {
obj.bar?.() //error
} catch (err) {
console.log("bar cannot be called");
}
.as-console-wrapper {
max-height: 100% !important
}
However, in terms of async semantics, there is a difference: await will force an async function to pause. While not having await will run the function until another await is encountered or the function finishes and a result is produced.This can lead to very subtle bugs. Consider this case when the behaviour overlaps - there is a save() method, so both functions pause to await its result:
let x = 1;
async function testIf(someObject) {
console.log("testIf 1:", x); //some external variable
if (someObject.save){
await someObject.save();
}
console.log("testIf 2:", x); //some external variable
}
async function testOptional(someObject) {
console.log("testOptional 1:", x); //some external variable
await someObject.save?.();
console.log("testOptional 2:", x); //some external variable
}
const obj = {
save() { return Promise.resolve(); }
}
testIf(obj);
testOptional(obj);
x = 2; //change external variable
The behaviour is consistent: both of these will stop at the line with await, which will yield the execution, which then processes the new assignment to x, so then when both functions resume, they both read the new value of x. This is expected.
Now, consider what happens if the await line is not hit in the if version:
let x = 1;
async function testIf(someObject) {
console.log("testIf 1:", x); //some external variable
if (someObject.save){
await someObject.save();
}
console.log("testIf 2:", x); //some external variable
}
async function testOptional(someObject) {
console.log("testOptional 1:", x); //some external variable
await someObject.save?.();
console.log("testOptional 2:", x); //some external variable
}
const obj = {}
testIf(obj);
testOptional(obj);
x = 2;
The semantics changed. For the if version the await line is not processed, thus the execution does not yield until the function finishes, thus it reads the value of x before the reassignment both times. The version that uses optional chaining preserves its semantics even if save is not present - it still encounters the await and still yields.
In summary, having optionally asynchronous operation is the path to madness. I would suggest avoiding it at all costs.
Read more about this:
Callbacks, synchronous and asynchronous by Havoc
Designing APIs for Asynchrony by Isaac Z. Schlueter
Intentionally unleashing Zalgo with synchronous promises by Daniel Brain
And yes, the code I showed is also probably bad - you most likely should not rely on external values. Yet, sometimes you have to. And even if you do not rely on them, in the future, somebody consuming your code might. It is best to just avoid Zalgo in the first place and have more predictable code.
The best answer to this (I think) would be if you are working in a group where the group has decided not to use ?. because not everyone understands it. Otherwise, no. The second isn't safer
It should be fine as you would await undefined.
Some considerations from the documentation:
const result = someInterface.customMethod?.();
if there is a property with such a name which is not a function, using ?. will still raise a TypeError exception "someInterface.customMethod is not a function".
Note: If someInterface itself is null or undefined, a TypeError exception will still be raised ("someInterface is null"). If you expect that someInterface itself may be null or undefined, you have to use ?. at this position as well: someInterface?.customMethod?.().
I have a function as below:
function callme(x,y) {
return function() {
console.log("value of x = " + x);
console.log("value of y = " + y);
}
}
I would like to add the above function to an array and then execute them
var steps = [];
steps.push(callme(1,2));
steps.push(callme(2,3));
steps[0]; // should execute first function
steps[1]; // should execute second function
For some reason the parameters I am passing to the function are not getting stored.
Anyone anyclues as to what I might be doing wrong ?
You're not actually calling the methods. Calling methods involves using the bracket syntax as shown below:
steps[0](); // should execute first function
steps[1](); // should execute second function
Edit
Jared has kindly worked up a JSFiddle.
Second Edit
In your comments you've asked for added callback functionality. Even though this should probably be a separate question, I'll throw a bone for now:
function callme(x, y, callback) {
return function() {
console.log("value of x = " + x);
console.log("value of y = " + y);
callback();
}
}
I'm assuming you'll want to call the functions programmatically in order (from your array), so you'll probably need something like this:
var steps = [];
steps.push(callme(1, 2, next));
steps.push(callme(2, 3, next));
var i = -1;
function next(){
i++
if(i < steps.length){
steps[i]();
}
}
next();
It should be noted though that this sort of sequential calling of methods can be a slippery slope. Mainly because your callback method is being called before the last callback has finished executing, leading to possible stack overflow errors.
You're better off looking into design patterns: middleware and promises is a good place to start.
you should call like this
steps[0]();
steps[1]();
In order to execute each function, you need to invoke it.
So this line steps[0] should actually look like this steps[0]()
EDITED. Bad answer on my part as I somehow overlooked the fact that callme() indeed returns a function.
My group is starting a new project. We are thinking about organizing the JavaScript in such a way so that any JavaScript errors don't get lost but rather get caught and sent to the server to be logged. For namespacing I want to keep it simple so I'm using something like this:
var my_namespace = function() {
function myFunction(input) {
if (input < 0) {
throw "input must be positive";
}
return 'result';
}
return {myFunction: myFunction};
} ();
So now I can invoke my_namespace.myFunction(-22) but when the error will be thrown it will get lost. There will be many namespaces each one in it's own .js file (maybe somebody has a better idea about namespace schema).
So, my question is, how to like "surround" namespaces so that errors will not get lost?
Actually #Relic gave a good idea. I'm going to write below the code that will create the namespace "my_namespace" and surround the initialization by jQuery with try-catch:
var my_namespace = function() {
function init() {
throw "an exception during initialization";
}
return {init: init};
} ();
$(document).ready(function() {
try {
my_namespace.init();
} catch (e) {
// handle error
}
});
I'm going to experiment with what happens after it does initialization, that is, with the event handling.
Yep, just as I thought, event handling exceptions will not be caught. I'll research some more and return.
Two options for you:
Wrap Everything
You can wrap all of your code with try/catch blocks. This isn't as tedious as it sounds. There are two aspects of this: Wrapping your main code, and wrapping code that runs in response to events (user events, timer events, etc.). You can either do that manually, or you can give yourself a framework for doing it.
This doesn't have to be a pain at all. For instance, for the first part, just wrap a try/catch around your main code:
(function() { // (If you don't use scoping functions, just ignore this and the last line
try {
// Your code here
}
catch (e) {
reportException(e);
}
function reportException(exception) {
try {
// Do whatever you want to do to report the exception here.
}
catch (e) {
// Let the browser report it
throw 'Error handling exception: ' + exception;
}
}
})();
For the second part (catching exceptions in event handlers and code fired with setTimeout and similar), you can either always manually use try/catch blocks in all of your code (which is frequently what you want to do anyway), and possibly use a central function that wraps your event handlers to make sure uncaught exceptions are caught and handled, like this:
function makeHandler(handler) {
eventHandler.original = handler;
return eventHandler;
function eventHandler(event) {
try {
// Trigger the handler
return handler.call(this, event);
}
catch (e) {
// Handle event handler exception
reportException(e);
}
}
}
(There are more features you might add to that, but those are the basics.)
For public methods, you can use something quite similar to makeHandler:
function makePublic(method) {
publicMethod.original = method;
return publicMethod;
function publicMethod() {
try {
// Trigger the actual member
return method.apply(this, arguments);
}
catch (e) {
// Handle reporting the exception
reportException(e);
// Then probably re-throw it so the calling code
// sees it
throw e;
}
}
}
Bringing that all together, this code:
var Namespace = (function() {
var NS = {};
// Some setup
doSomething();
doSomethingElse();
if (/* Some condition */) {
doYetAnotherThing();
}
// Export public methods
NS.foo = foo;
NS.bar = bar;
function doSomething() {
var element = document.getElementById("foo");
// Note, next line could throw if element doesn't exist
element.addEventListener("click", function(event) {
// Handling click
var other = element.getElementsByTagName('input')[0];
element.innerHTML = other.value; // Could throw if `other` not there
}, false);
}
// ...other functions, including `foo` and `bar`...
// Return the namespace object
return NS;
})();
Turns into:
var Namespace = (function() {
var NS = {};
try {
// Some setup
doSomething();
doSomethingElse();
if (/* Some condition */) {
doYetAnotherThing();
}
// Export public methods
NS.foo = makePublic(foo);
NS.bar = makePublic(bar);
}
catch (e) {
reportException(e);
}
function doSomething() {
var element = document.getElementById("foo");
// Note, next line could throw if element doesn't exist
element.addEventListener("click", makeHandler(function(event) {
// Handling click
var other = element.getElementsByTagName('input')[0];
element.innerHTML = other.value; // Could throw if `other` not there
}), false);
}
// ...other functions, including `foo` and `bar`...
// ...`reportException`, `makeHandler`, `publicMethod`...
// Return the namespace object
return NS;
})();
So it's not that much impact.
You always want to use more targeted try/catch as part of your logic, but you can also use these global try/catch blocks to catch anything unexpected (like those silly bugs that sometimes slip into the catch block!), etc.
There are several advantages to this approach:
It works on all browsers.
You can throw things other than strings (more structured exceptions), and they'll still be
objects when you catch them.
If an error reaches the browser level, you know it's not in your code, or it's in your exception reporting code.
Use window.onerror
If for whatever reason the above isn't to your taste, a little-known feature of the browser environment is the fact that you can trap any uncaught error by assigning a function to window.onerror (live example described and linked below):
window.onerror = globalErrorHandler;
function globalErrorHandler(errorMsg, url, lineNumber) {
// Do something with the error here
}
This works in most browsers, but not all, and suffers from the fact that chaining these sorts of error handlers isn't natively supported (you have to do it yourself) and by the time the error reaches your code, it's already been turned into a string (a pain if you're using more structured exception objects).
Details on the MDC page for it, including how to play nice with others; slightly modified example:
function addWindowErrorHandler(handler) {
var previous = window.onerror;
window.onerror = function(errorMsg, url, lineNumber) {
var returnValue = false,
handled = false;
// Call the handler
try {
returnValue = handler(errorMsg, url, lineNumber);
}
catch (e) {
// Eat the error
}
// Hand off to previous
if (!returnValue && previous) {
try {
returnValue = previous(errorMsg, url, lineNumber);
}
catch (e) {
// Just eat it
}
}
// Done
return returnValue;
};
}
Just call that with a reference to your handler function, and have your handler function return true if the error was yours to handle, false otherwise.
To know whether the error is yours or not, you might consider putting a marker in the string (sadly, it'll be a string by the time it reaches the onerror handler, even if you threw some other object type). So you might use a worker function for the whole module that adds a marker, e.g.:
function myException(msg) {
return '*Marker* ' + msg;
}
Then
throw myException('cannot be negative');
and your handler would do
if (String(error).indexOf('*Marker*') >= 0) {
// It's ours
// ...handle it...
// Flag that we handled it
return true;
}
Unfortunately, even though you process the error, I'm not aware of any way to suppress it (the script still stops executing at that point).
You could even have Exception objects you construct that accept a message and a nested exception if you like. Just be sure to handle toString on them, because (again) by the time the error gets to the error handler, it's already been turned into a string.
Live example
I'd recommend a block of code that can monkey patch any function calls (nb untested):
(function (namespace) {
var addTryCatch = function (delegate) {
try {
delegate.apply(this, arguments);
} catch {
// standard code here
}
};
for (var propName in namespace) {
var prop = namespace[propName];
if (typeof prop === 'function') {
namespace[propName] = addTryCatch(namespace[propName]);
}
}
}(yourNamespace));
Any recursion could be added if necessary.
My Official answer:
<input type="button" id="btn" name="dont click me" value="dont click me" />
var _ns = { init: function() {
this.events();
},
events: function(){
$("#btn").on('click mouseover', function(event){
if(event.type != "mouseover"){
_ns.error.alert("Annnd you clicked me anyways");
}else{
_ns.error.console("nice mouseover skillz");
}
});
},
error:{
console:function (Error) {
console.log("Error: "+Error);
},
alert: function(Error){
alert("Error: "+Error);
}
}
};
$(document).ready(function() {
_ns.init();
});
After spending some time looking for the solution I came to the following conclusion. You must use window.onerror, there is no other way.
a general question, but the code in question is this:
have an error routine that is thrown to - handles exeptions:
MyObj.prototype.err = function( msg ) { ... throw(msg); }
so to throw,
if( mybad ) this.err( 'my message' );
would like err() to behave differently depending on whether a function is or is not in the call stack.
for example, could be
funcA() -> func2() -> func3() -> err()
versus
funcB() -> func3() -> err()
if funcA were upstream, would like to alert the user and stop; whereas if funcB, would like to write the message to console and continue.
realize other ways to solve the problem, but imho bad luck to create (and maintain) state space that can be deduced from the environment
I'm not sure what you are trying to solve, but I am pretty sure there is a better way to do it than this.
That being said, here's one way of tracing functions and checking the callstack without resorting to parsing of browser-specific stack traces:
var callstack = [];
function traced(name, func) {
return function () {
callstack.push(name);
func.apply(this, arguments);
callstack.pop();
}
}
and use it like this:
var a = traced("a", function () {
b();
});
var b = traced("b", function () {
c();
});
var c = traced("c", function () {
var s = callstack.join("<br>");
document.getElementById('output').innerHTML = s;
});
document.getElementById('a').onclick = a;
document.getElementById('b').onclick = b;
You can check it out on fiddle here: http://jsfiddle.net/AsrSp/
In Chrome you could do:
var err = function( msg ) {
// ...
var error = new Error();
var stack = error.stack;
// Do some string manipulation with stack
// mayThrow = 'funcB is in stack'
if (mayThrow) {
throw(msg);
}
};
May I point out that I consider this a very bad practice. I think you should catch the error in FuncB in stead of defining FuncB as a function not to throw from in err. It is less code and much easier to manage. So:
var err = function( msg ) {
// ...
throw(msg);
};
var func3 = function() {
// ...
err('Double rainbow');
};
var funcB = function() {
try {
func3();
catch(e) {
console.log(e);
}
};
Try to understand why this is the better solution, it is about defining responsibilities for which functionality belongs to which function. This is exactly why exception and handling is designed the way it is.
Ok, this may sound a bit crazy but hear me out :)
I would like to do the following in javascript:
define START_OF_EVERY_FUNCTION = "try {"
define END_OF_EVERY_FUNCTION = "} catch () {}"
function TEST () {
START_OF_EVERY_FUNCTION
// rest of function
END_OF_EVERY_FUNCTION
}
Basically, can I define a list of javascript lines (code) and include them as above? I'm looking for a technique versus comments about whether this is a good idea or not or debate over wrapping all functions in a try/catch block.
I know about eval(), but I dont think you can eval statements like the above.
This might be goofy but you could define a master function and run other functions through it by passing them in.
var execute = function(func){
alert('before');
func();
alert('after');
};
function sayHi(){
alert('hi there');
}
execute(sayHi);
As requested, an example with passing arguments.
var execute = function(func){
alert('before');
var ret = func.apply(null, Array.prototype.slice.call(arguments, 1));
alert('after');
};
function saySomething(sayWhat){
alert(sayWhat);
}
execute(saySomething,'hey there');
That is not allowed in JavaScript.
You could extend the Function prototype:
Function.prototype.tryThis = function() {
try {
this();
}catch(ex){
alert('Caught '+ex);
};
};
function tryIt() {
alert('Inside tryIt');throw "My Error from tryIt";
}
tryIt.tryThis();
You need to look into aspect oriented programming for JavaScript. You can create hooks for function entry and exit. Tools like JSUnit do this for example.
I think you can do this with the "new Function" operator. I've never used it myself, since I'm not clinically insane, but I believe you can pass it a string which it will evaluate and use as the function body. You can also get the code for each function by calling myFunction.toString(). So put together, it'd be something like this:
var functionsToMessUp = ['myFunc1', 'myFunc2'];
for (var i = 0; i < functionsToMessUp.length; ++i) {
var theFunc = window[functionsToMessUp[i]]; // assuming they're in global scope
window[functionsToMessUp[i]] = new Function(
START_OF_EVERY_FUNCTION
+ theFunc.toString()
+ END_OF_EVERY_FUNCTION
);
}
Now, the above almost certainly won't work - there's parameters and other things to take into consideration, and I don't even think that's how the new Function constructor works, but if you really want to go down this path (which I really don't recommend), then this might be a good starting point for you.
Maybe something like this?
function tryCatch(callback) {
try {
callback();
} catch() {}
}
var myFunction = function() {
// do some stuff
};
tryCatch(myFunction);