JavaScript infrastructure such that propagated errors don't get lost - javascript

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.

Related

Use helper modules for repeated, ordered tasks when functional testing in intern

I'm trying to create a module that will fill in form inputs when functional testing, and I'd like to be able to call it from multiple test suites.
Pseudo code for the helper file (helper.js)
module.exports = {
fillForm: function() {
this.findByCssSelector('#firstname')
.click()
.pressKeys('John')
.end()
},
anotherFunction: function() {
// more code
}
}
In the spec for the functional test, I load that module as helper and I can see it execute. However, it seems I can't use this syntax and guarantee that the chained steps execute in the defined order:
'Test filling form data': function() {
return this.remote
.get(require(toUrl(url))
// should happen first
.then(helper.fillForm)
// should happen second
.then(helper.anotherFunction)
// only after the above should the click happen
.findByCsSelector('#submit')
// click evt should show the #someElement element
.click()
.findByCssSelector('#someElement')
.getComputedStyle('display')
.then(style) {
// assertions here
}
It seems that the promise chaining allows the click event to happen before the then callbacks have executed. Is this sort of flow possible with intern?
UPDATE:
For the moment, working around this with this sort of code:
var remote = initTest.call(this, url);
return helpers.fillForm1Data.call(remote)
.otherChainedMethodsHere()
.moreChainedMethods()
.then() {
// assertion code here
where the initTest method does url fetching, window sizing, clearing data, and the fillForm1Data does as you'd expect. But the syntax is pretty ugly this way.
Your helper is not returning any value so it is treated as a synchronous callback and the next thing in the chain is executed immediately. You also cannot return this from a promise helper or it will cause a deadlock (because the Command promise will be waiting for itself to resolve—Intern will throw an error instead if you try to do this), so you need to create a new Command and return that if you want to use the chained Command interface within your helper:
module.exports = {
fillForm: function() {
return new this.constructor(this.session)
.findByCssSelector('#firstname')
.click()
.pressKeys('John');
},
anotherFunction: function() {
// more code
}
};
You can also just return from this.session instead if you don’t care about the convenience of the Command API and can deal with normal promise callback chains:
module.exports = {
fillForm: function() {
var session = this.session;
return session.findByCssSelector('#firstname')
.then(function (element) {
return element.click();
})
.then(function () {
return session.pressKeys('John');
});
},
anotherFunction: function() {
// more code
}
};

How to not use the first parameter of a method call and still pass JSLint?

I'm having to call a method with two parameters, but I'm only using the 2nd one. My code looks like this:
function trapEvent(resolve, reject) {
event_callback = function (evt) {
evt.stopPropagation();
if (allowDefault !== true) {
evt.preventDefault();
}
cancelResolver();
callback_promise = new Promise()
.cancellable()
.then(function () {
return callback(evt);
})
.then(null, function (error) {
if (!(error instanceof Promise.CancellationError)) {
canceller();
reject(error);
}
});
};
util.startListenTo(target, type, event_callback, useCapture);
}
return new Promise(trapEvent, canceller);
As I'm "locking" my event inside a promise, which can only be rejected or cancelled, I'm never using the resolve method, which JSlint rightfully complains about. However, according to MDN es6 Promise spec, I need to provide both resolve and reject in the Promise callback method.
Question:
How can I make this method pass while keeping resolve?
I think the best way to go is update your jshint.json file and configure this to be allowed.
The "unused" property is the one you are looking for. It could be tweaked to either contain the following values:
false - don't check for unused variables
true - "vars" + check last function param
"vars" - skip checking unused function params
"strict" - "vars" + check all function params
It seems to me that it currently has been set to "strict". You might want to change that to true or "vars". The latter would be useful for cases where you would not want to call the reject callback and only call the resolve method.
In case you just want to disable jshint in total for just the given line, you could do the following:
function trapEvent(resolve, reject) { //jshint ignore:line
Yeah, for jslint, what you're looking for is unparam -- /*jslint unparam: true*/
Here it is in context. I'm guessing at globals, etc, and I'm assuming you're using the callback_promise somewhere later on. Note the unparam at the end of the first line.
/*jslint white:true, sloppy:true, unparam: true */
/*global allowDefault, cancelResolver, callback, canceller, util, target, type, useCapture */
function trapEvent(resolve, reject) {
var event_callback, callback_promise;
event_callback = function (evt) {
evt.stopPropagation();
if (allowDefault !== true) {
evt.preventDefault();
}
cancelResolver();
callback_promise = new Promise()
.cancellable()
.then(function () {
return callback(evt);
})
.then(null, function (error) {
if (!(error instanceof Promise.CancellationError)) {
canceller();
reject(error);
}
});
};
util.startListenTo(target, type, event_callback, useCapture);
// ... assuming you're using callback_promise later
}
There [used to be] other, slightly hipster ways of working around this, like using the arguments property in a function, where you could leave both parameters out of the function definition entirely, and then pull what's now reject out once you're in the code.
/*jslint white:true, sloppy:true, browser:true */
function trapEvent() {
var reject = arguments[1];
reject();
}
var fnTest = function () { window.alert("Used"); };
trapEvent("unused", fnTest);
.. but honestly, that's really hacky. And now that I test that out, recent versions of JSLint (maybe closing the accidental loophole starting July 3rd of last year?) don't accept it any more either, thankfully.
I recommend using unparam, but only in those files where you don't have control of the function signature for whatever reason, as in your use case here.

How to handle errors in knockout subscription

I'm writing an app using knockout and I'd like to be able to catch any errors in my code which are run inside of knockout, for example a subscription.
Currently I have a knockout subscription:
var myObservable = ko.observable();
myObservable.subscribe(function (val) {
// Code here is error prone
});
I'd like to be able to use the above pattern throughout my app but be able to catch any errors thrown in the subscription callback.
My current solution is to wrap the ko.subbscribable.fn.subscribe function with an error handler, like so:
var _subscribe = ko.subscribable.fn.subscribe;
ko.subscribable.fn.subscribe = function (callback) {
if (arguments.length != 1) return _subscribe.apply(this, arguments);
else return _subscribe.apply(this, [function () {
try
{
callback.apply(this, arguments);
}
catch (err) {
// handleError is a function in my code which will handle the error for me
handleError(err);
}
}]);
};
My question is are there any hidden side affects with this approach, or is there a better approach I'm missing.
This is good approach, basically called duck punching, see great explanation from Paul Irish
http://www.paulirish.com/2010/duck-punching-with-jquery/
I would only update the code to handle error also in case more arguments are passed into subscribe function, like this
var _subscribe = ko.subscribable.fn.subscribe;
ko.subscribable.fn.subscribe = function () {
try {
return _subscribe.apply(this, arguments);
}
catch (err) {
// handleError is a function in my code which will handle the error for me
handleError(err);
}
};

Check for function called

Just wondering if there is anyway to fire some code when a function is called, without adding the code to the function, for example:
function doSomething(){
//Do something
}
//Code to call when doSomething is called
You can wrap the function :
(function(){
var oldFunction = doSomething;
doSomething = function(){
// do something else
oldFunction.apply(this, arguments);
}
})();
I use an IIFE here just to avoid polluting the global namespace, it's accessory.
Well, yes, it's not actually hard to do. The crucial thing is that a function's name is just an identifier like any other. You can redefine it if you want to.
var oldFn = doSomething;
doSomething = function() {
// code to run before the old function
return oldFn.apply(this, arguments);
// code to run after the old function
};
NB that it's better to do oldFn.apply(this, arguments) rather than just oldFn. In many cases it won't matter, but it's possible that the context (i.e. the value of this inside the function) and the arguments are important. Using apply means they are passed on as if oldFn had been called directly.
What about something like:
function doSomething(){
doSomething.called = true;
}
//call?
doSomething();
if(doSomething.called) {
//Code to call when doSomething is called
}
I know you said you don't want to modify the original function, but consider adding a callback. Then you can execute code based on different results in your function (such as onSucess and onError):
function doSomething(onSuccess, onError){
try {
throw "this is an error";
if(onSuccess) {
onSuccess();
}
} catch(err) {
if(onError) {
onError(err);
}
}
}
Then, when you call doSomething, you can specify what you want done with inline functions:
doSomething(function() {
console.log("doSomething() success");
}, function(err) {
console.log("doSomething() error: " + err);
});

Implementing exception handling in JavaScript

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();

Categories