Related
I am trying to load some content using require.js. If the content doesn't exist I'd like to catch the error and notify the user.
In firebug I can see two errors:
"NetworkError: 404 Not Found
...and then a few seconds later:
var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#
Load timeout for modules: modules/messages/messages
http://requirejs.org/docs/errors.html#timeout
My code resembles:
require([path], function(content){
//need to catch errors as this will not be called;
});
How would one bind to requirejs events? Any idea?
It is also possible to use errbacks to have customized error handling appropriate to the specific use of require. Errbacks are documented here http://requirejs.org/docs/api.html#errbacks. Basically, you can add to require a function to be called if the load fails. It comes right after the function to be called if the load is successful.
Chin's case could be handled as:
require([path], function(content){
//need to catch errors as this will not be called;
}, function (err) {
//display error to user
});
Here's an example that tries loading from multiple places:
require([mode_path], onload, function (err) {
if (mode_path.indexOf("/") !== -1)
// It is an actual path so don't try any further loading
throw new Error("can't load mode " + mode_path);
var path = "./modes/" + mode_path + "/" + mode_path;
require([path], onload,
function (err) {
require([path + "_mode"], onload);
});
});
In this example onload would be the function called once the required code loads, and mode_path is a string identifying the mode. What you see there is code attempting to load a mode module for an editor from 3 different locations. If mode_path is foo, it will try to load foo, then ./modes/foo/foo and then ./modes/foo/foo_mode.
The example at requirejs.org shows how one might handle a case where they want to try multiple locations for a resource they want to make available with a well-known identifier. Presumably the entire code-base in that example requires jQuery by requiring "jquery". Whatever location jQuery happens to be located at, it becomes available to the whole code-base as "jquery".
My example does not care about making the mode known to the entire code-base through a well-known identifier because in this specific case there's no good reason to do so. The onload function stores the module it gets into a variable and the rest of the code base gets it by calling a getMode() method.
set the requirejs onError function:
requirejs.onError = function (err) {
if (err.requireType === 'timeout') {
// tell user
alert("error: "+err);
} else {
throw err;
}
};
If you want to setup an event you could bind to and trigger a global object. Such as:
$("body").bind("moduleFail",function(){
alert("Handling Event")
});
requirejs.onError = function (err) {
if (err.requireType === 'timeout') {
$("body").trigger({type:"moduleFail",err:err})
} else {
throw err;
}
};
require(["foo"],function(foo){
alert("loaded foo" + foo)
})
Did you try to override the requirejs.onError like shown here?
It worked for me after setting catchError as true like this:
require.config({catchError:true});
before calling any define() or require() functions.
You can use the requirejs.onError function as :
requirejs.onError = function (err) {
if (err) {
//Reload
}
else {
throw err;
}
};
You can also use err.requireType to catch specific errors like timeouts
I would like to pass errors to an alert to warn the user they made mistake in their code even if they don't have console open.
var doc=(frame.contentWindow.document || obj.contentDocument|| obj.contentWindow);
var head = doc.getElementsByTagName('head')[0];
var scriptElement = doc.createElement('script');
scriptElement.setAttribute('type', 'text/javascript');
scriptElement.text = scripts;
try{
head.appendChild(scriptElement);
}
catch(e){ alert("error:"+e.message +" linenumber:"+e.lineNumber);}
The appendChild throws an error when the scripts contain an error. It goes straight to the console though, and I want it to display in an alert, because it is for kids and they might not check the console. The try catch block does not catch the error.
I tried it with eval(scripts).
try{
eval(scripts);} catch(e){ alert("error:"+e.message +" linenumber:"+e.lineNumber);}
this does work but it means that the code is executed twice, and that is very inconvenient in some cases.
I tried monkey patching the console.error:
console.log=function(){alert("taking over the log");}
console.error=function(){alert("taking over the log");}
but that only works when I literally use console.error. Not when an actual error is thrown.
What function sends the error to the console in the case of a real error,if it isn't console.error? and can I access it and change it?
Any ideas? Help would be really appreciated.
Thanks Jenita
Whilst try ... catch will work on the code that the script runs initially, as Jenita says it won't catch Syntax Errors, and also it won't catch errors thrown by callback functions which execute later (long after the try-catch has finished). That means no errors from any functions passed to setTimeout or addEventListener.
However, you can try a different approach. Register an error listener on the window.
window.addEventListener("error", handleError, true);
function handleError(evt) {
if (evt.message) { // Chrome sometimes provides this
alert("error: "+evt.message +" at linenumber: "+evt.lineno+" of file: "+evt.filename);
} else {
alert("error: "+evt.type+" from element: "+(evt.srcElement || evt.target));
}
}
This will be called when an exception is thrown from a callback function. But it will also trigger on general DOM errors such as images failing to load, which you may not be interested in.
It should also fire on Syntax Errors but only if it was able to run first so you should put it in a separate script from the one that may contain typos! (A Syntax Error later in a script will prevent valid lines at the top of the same script from running.)
Unfortunately, I never found a way to get a line number from the evt in Firefox. (Edit: Poke around, I think it might be there now.)
I discovered this when trying to write FastJSLogger, an in-page logger I used back when the browser devtools were somewhat slow.
Desperate to catch line numbers, I started to experiment with wrappers for setTimeout and addEventListener that would re-introduce try-catch around those calls. For example:
var realAddEventListener = HTMLElement.prototype.addEventListener;
HTMLElement.prototype.addEventListener = function(type,handler,capture,other){
var newHandler = function(evt) {
try {
return handler.apply(this,arguments);
} catch (e) {
alert("error handling "+type+" event:"+e.message +" linenumber:"+e.lineNumber);
}
};
realAddEventListener.call(this,type,newHandler,capture,other);
};
Obviously this should be done before any event listeners are registered, and possibly even before libraries like jQuery are loaded, to prevent them from grabbing a reference to the real addEventListener before we have been able to replace it.
Ok so the less elegant but highly efficient way of doing this is 'refactoring' your innate console functions. Basically any error or warnings you get are being outputted there by a javascript function that is pretty similar to the familiar console.log() function. The functions that I am talking about are console.warn(), console.info() and console.error(). now let's 're-map' what each of those do:
//remap console to some other output
var console = (function(oldCons){
return {
log: function(text){
oldCons.log(text);
//custom code here to be using the 'text' variable
//for example: var content = text;
//document.getElementById(id).innerHTML = content
},
info: function (text) {
oldCons.info(text);
//custom code here to be using the 'text' variable
},
warn: function (text) {
oldCons.warn(text);
//custom code here to be using the 'text' variable
},
error: function (text) {
oldCons.error(text);
//custom code here to be using the 'text' variable
}
};
}(window.console));
//Then redefine the old console
window.console = console;
Now, generally I would highly advise against using something like this into production and limit it to debugging purposes, but since you are trying to develop a functionality that shows the output of the console, the lines are blurry there, so I'll leave it up to you.
You could wrap the script in its own try/catch, something like:
var doc=(frame.contentWindow.document || obj.contentDocument|| obj.contentWindow);
var head = doc.getElementsByTagName('head')[0];
var scriptElement = doc.createElement('script');
scriptElement.setAttribute('type', 'text/javascript');
scriptElement.text = "try{"+scripts+"}catch(e){console.error(e);alert('Found this error: ' + e +'. Check the console.')}"
head.appendChild(scriptElement);
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.
Example code:
var connection = null;
function onConnect(status) {
im_a_big_error.log('wtf');
// Why it doesn't throw me an error here ??
}
$().ready(function() {
connection = new Strophe.Connection('http://localhost:8080/http-bind');
connection.connect('admin#localhost', 'admin', onConnect);
});
It doesn't throw me an error in my Chrome console.
Do you have an idea to resolve this issue?
Yes, Strophe often catch errors by itself and currently doesn't provide any ability to get connection error information. While error catching is ok, the impossibility of catching errors by yourself is not very good. But you can fix it with the following code:
$().ready(function() {
connection = new Strophe.Connection('http://localhost:8080/http-bind');
connection._hitError = function (reqStatus) {
this.errors++;
Strophe.warn("request errored, status: " + reqStatus + ",
number of errors: " + this.errors);
if (this.errors > 4) this._onDisconnectTimeout();
myErrorHandler(reqStatus, this.errors);
};
connection.connect('admin#localhost', 'admin', onConnect);
});
where myErrorHandler is your custom connection error handler.
Yes, strophe swallows errors. Worse; After an error is thrown, the callback won't return true as it should, and strophe will remove the handler. As soon as an error occurs, the callback will never be called again.
I found the code from the current answer a bit hard to use. Internally, we use the following wrapper for every callback;
function callback(cb) {
// Callback wrapper with
// (1) proper error reporting (Strophe swallows errors)
// (2) always returns true to keep the handler installed
return function() {
try {
cb.apply(this, arguments);
} catch (e){
console.log('ERROR: ' + (e.stack ? e.stack : e));
}
// Return true to keep calling the callback.
return true;
};
}
This wrapper would be used as following in the code of the question;
connection.connect('admin#localhost', 'admin', callback(onConnect));
I've been playing with Strophe for a while now and I had to modify its default error handling routine to fit our needs
Strophe.js - log function - by default contains nothing - I added calls to my server side logging service for level === ERROR and level === FATAL
Strophe.js - run function - the default behavior for error is to remove the handler and to rethrow the error - since I already log the error server side I don't rethrow the error and decided to keep the handler (even if it failed). This behavior could make sense (or not) depending on your own implementation - since I use custom messages and have a rather complicated message processing routine I don't want the client to stop just because a message was not properly formatted when sent so I want to keep the handler, error or not. I replace the throw e line inside the run function with result = true;
Strope.js _hitError - as I mentioned, I don't want the client to ever disconnect so I rewrote the default behavior to never disconnect (no matter how high the error counter)
Hope these thoughts are of help to others - leave a comment if you have questions/want details.
I had a similar problem which I fixed using the approach given by tsds above. However with minimal modification. I created two connect methods one as connect and the other as connect_bak I placed the script
this.connection._hitError=function (reqStatus) {
client.connect_bak();
};
in my connectHandler function as well as the connect function. Such that the function is always binded on connect.
What is the best technique for catching ALL exceptions thrown within JavaScript?
Obviously, the best technique is to use try...catch. But with ansynchronous callbacks and so forth, that can get tricky.
I know IE and Gecko browsers support window.onerror, but what about Opera and Safari?
Here are a bunch of test-cases that I would like to have a central exception handling solution for:
// ErrorHandler-Test1
var test = null;
test.arg = 5;
// ErrorHandler-Test2
throw (new Error("Hello"));
// ErrorHandler-Test3
throw "Hello again";
// ErrorHandler-Test4
throw {
myMessage: "stuff",
customProperty: 5,
anArray: [1, 2, 3]
};
// ErrorHandler-Test5
try {
var test2 = null;
test2.arg = 5;
} catch(e) {
ErrorHandler.handleError(e);
}
// ErrorHandler-Test6
try {
throw (new Error("Goodbye"));
} catch(e) {
ErrorHandler.handleError(e);
}
// ErrorHandler-Test7
try {
throw "Goodbye again";
} catch(e) {
ErrorHandler.handleError(e);
}
// ErrorHandler-Test8
try {
throw {
myMessage: "stuff",
customProperty: 5,
anArray: [1, 2, 3]
};
} catch(e) {
ErrorHandler.handleError(e);
}
If you think of any other test-cases, please mention them. Several of these cases mention a ErrorHandler.handleError method. This is just a suggested guideline when using try...catch.
If you use a library like jQuery for assigning all your event handlers, you can use a combination of window.onerror and wrapping the jQuery event handler code and on ready function with an error handling function (see: JavaScript Error Tracking: Why window.onerror Is Not Enough).
window.onerror: catches all errors in IE (and most errors in Firefox), but does nothing in Safari and Opera.
jQuery event handlers: catches jQuery event errors in all browsers.
jQuery ready function: catches initialisation errors in all browsers.
WebKit (Safari, Chrome, etc) now appears to support onerror.
Original post: As far as I know, WebKit/Safari does not support the onerror event. Which is a damn shame.
Actually, the jquery approach isn't so bad. See:
http://docs.jquery.com/Events/error#fn
and:
$(window).error(function(msg, url, line){
$.post("js_error_log.php", { msg: msg, url: url, line: line });
});
Catch all exceptions with your own exception handler and use instanceof.
$("inuput").live({
click : function (event) {
try {
if (somethingGoesWrong) {
throw new MyException();
}
} catch (Exception) {
new MyExceptionHandler(Exception);
}
}
});
function MyExceptionHandler(Exception) {
if (Exception instanceof TypeError ||
Exception instanceof ReferenceError ||
Exception instanceof RangeError ||
Exception instanceof SyntaxError ||
Exception instanceof URIError ) {
throw Exception; // native error
} else {
// handle exception
}
}
MyExcetpionHandler will throw native error as there is no try-catch block.
Visit http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/
try-catch is not always the best solution. For example, in Chrome 7.0 you lose the nice stack trace in the console window. Rethrowing the exception does not help. I don't know of any solution which preserves stack traces and letting you react on exception.
With a little bit of work it's possible to get stacktraces that are reasonably complete in all browsers.
Modern Chrome and Opera (i.e. anything based around the Blink rendering engine) fully support the HTML 5 draft spec for ErrorEvent and window.onerror. In both of these browsers you can either use window.onerror, or (amazingly!) bind to the 'error' event properly:
// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) {
console.log(message, "from", error.stack);
// You can send data to your server
// sendData(data);
};
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (e) {
console.log(e.error.message, "from", e.error.stack);
// You can send data to your server
// sendData(data);
})
Unfortunately Firefox, Safari and IE are still around and we have to support them too. As the stacktrace is not available in window.onerror we have to do a little bit more work.
It turns out that the only thing we can do to get stacktraces from errors is to wrap all of our code in a try{ }catch(e){ } block and then look at e.stack. We can make the process somewhat easier with a function called wrap that takes a function and returns a new function with good error handling.
function wrap(func) {
// Ensure we only wrap the function once.
if (!func._wrapped) {
func._wrapped = function () {
try{
func.apply(this, arguments);
} catch(e) {
console.log(e.message, "from", e.stack);
// You can send data to your server
// sendData(data);
throw e;
}
}
}
return func._wrapped;
};
This works. Any function that you wrap manually will have good error handling.
You can send data using image tag as follows
function sendData(data) {
var img = newImage(),
src = http://yourserver.com/jserror + '&data=' + encodeURIComponent(JSON.stringify(data));
img.crossOrigin = 'anonymous';
img.onload = function success() {
console.log('success', data);
};
img.onerror = img.onabort = function failure() {
console.error('failure', data);
};
img.src = src;
}
However you have to do backend to collect the data and front-end to visualise the data.
At Atatus, we are working on solving this problem. More than error tracking, Atatus provides real user monitoring.
Give a try https://www.atatus.com/
Disclaimer: I am a web developer at Atatus.
It is true that with modern browsers, hooking window.onerror for errors that bubble all the way to the top along with adding jQuery event handlers for Ajax errors will catch practically all Error objects thrown in your client code. If you're manually setting up a handler for window.onerror, in modern browsers this is done with window.addEventListener('error', callback),
while in IE8/9 you need to call
window.attachEvent('onerror', callback).
Note that you should then consider the environment in which these errors are being handled, and the reason for doing so. It is one thing to catch as many errors as possible with their stacktraces, but the advent of modern F12 dev tools solves this use case when implementing and debugging locally. Breakpoints etc will give you more data than is available from the handlers, especially for errors thrown by third-party libraries which were loaded from CORS requests. You need to take additional steps to instruct the browser to provide this data.
The key issue is providing this data in production, as your users are guaranteed to run a far wider array of browsers and versions than you can possibly test, and your site/app will break in unexpected ways, no matter how much QA you throw at it.
To handle this, you need a production error tracker which picks up every error thrown in your user's browsers, as they use your code, and sends them to an endpoint where the data can be viewed by you and used to fix the bugs as they happen. At Raygun (disclaimer: I work at Raygun) we've put a bunch of effort into providing a great experience for this, as there's many pitfalls and issues to consider that a naive implementation will miss.
For instance, chances are you'll be bundling and minifying your JS assets, which means that errors thrown from minified code will have junk stacktraces with mangled variable names. For this, you need your build tool to generate source maps (we recommend UglifyJS2 for this part of the pipeline), and your error tracker to accept and process these, turning the mangled stacktraces back into human-readable ones. Raygun does all this out of the box, and includes an API endpoint to accept source maps as they are generated by your build process. This is key as they need to be kept non-public, otherwise anyone could unminify your code, negating its purpose.
The raygun4js client library also comes with window.onerror for both modern and legacy browsers, as well as jQuery hooks out-of-the-box, so to set this up you only need to add:
<script type="text/javascript" src="//cdn.raygun.io/raygun4js/raygun.min.js" </script>
<script>
Raygun.init('yourApiKey').attach();
</script>
There's also a bunch of functionality built-in including the ability to mutate the error payload before it is sent, adding tags and custom data, metadata on the user who saw the error. It also takes the pain out of getting good stack traces from the above-mentioned third-party CORS scripts, which solves the dreaded 'Script Error' (which contains no error message, and no stack trace).
A more crucial issue is that due to the huge audience on the web, your site will generate many thousands of duplicate instances of each error. An error tracking service like Raygun has smarts to roll these up into error groups so you don't drown in a flood of notifications, and lets you see each actual error ready to be fixed.
I was also looking for error handling and stacktrace and logging for user actions this is what i found hope this also helps you
https://github.com/jefferyto/glitchjs