37

I want to be able to send myself all the javascript errors on a page. I am an extension developer, so the following has an emphasis on making sure the dom is ready before making calls to it.

I investigated adding some functionality to the throw to also send or mail the exceptions, but I didn't find this to be possible.

1:main solution to this, a window.onerror handler:

window.onerror = function(e, url, line){
  mailError('onerror: ' + e + ' URL:' + url + ' Line:' + line);
  console.error('\nLine ' + line + ':');
  setTimeout(function(){retry();}, 100); //mainly useful in content scripts for extensions, 
  return true; 
}

May also need to do same thing via jQuery:

$(window).error( 
  function(e, url, line){
    //handle error
  }
);

The downfall of this is that your code has stopped executing.

To avoid errors stopping execution, it's best to use callbacks to make sure code executes in a certain sequence, and to utilize events wherever possible. You can also protect dom calls with a few techniques

$(document).ready({
  //you usually won't get bad dom calls wrapping your code in this
});

You can also consider running code on window.onload

window.onload = function(){
  //you page will probably twitch upon executing code at this time
  //but you will almost never have a bad dom call
};

Another technique

if (document.getElementById('iNeedThisElement')) {
  //doin work!
  document.getElementById('iNeedThisElement').style.display = 'block';
} else {
  var stillNeedToTakeCareOfX = true; //false otherwise since it's undefined
  mailError('iNeedThisElement was unavailable...');
}

Using these techniques and just debugging your application, you should be fairly well off. Since console.error, .warn, and .log statements cannot be retrieved and reported back to your, a small alternative suite is provided below:

var Xe = { }; //Extreme error suite

function extraInfo(e){
   //e optional
   if(!e)e = true;

   //add an extra debug info, such as navigator or current URL
   return ' currentURL: '+ document.URL + 
        '\n userAgent: ' + navigator.userAgent + 
        '\n platform: '  + navigator.platform + 
        '\n userid: '    + localStorage.userid + 
        '\n language: '  + navigator.langauge + 
        '\n cookies?: '  + navigator.cookiesEnabled;
}

Xe.error = function(e){
  console.error(e); //maintain original functionality
  mailError('Xe err: ' + e + extraInfo() );
}


Xe.warn = function(e){
  console.warn(e);
  mailError('Xe warn: ' + e + extraInfo() );
}


Xe.log = function(e){
  console.log(e);
  mailError('Xe log: ' + e + extraInfo() );
}

As a last ditch, you can continually attempt to execute a chunk of code until it executes without errors. This is "2" below.

2:group code in large chunks and attempting to re-execute x seconds later after catching an error, or continue to next chunk of code

//defExe = DEFinitely EXEcute this code
  //functionArg, reference to a function holding a large chunk of code
  //seconds, timeout in milliseconds to re-attempt error free execution of this function
function defExe(functionArg, seconds) {
  //seconds is optional
  if (!seconds)seconds = 300;

  try {
    functionArg();
  } catch(e) {
    //mail the error plus extra info
    mailError('caught ' + e + ' attempting to re-execute ' + functionArg.name + ' in ' + seconds + ' milliseconds');

    //re-attempt to execute this code
    setTimeout(function(){ 
       defExe(functionArg, seconds); 
    }, seconds);
  }
}

this it is then used like

//array to group function chunks
var fn = [ ];

fn[1] = function (){
  //a large chunk of javascript
}
defExe(fn[1]);

fn[2] = function(){
  //another chunk of your program
}
defExe(fn[2]);

#2 Summary: Group code in functions and run in try-catch block, repeating if an errors are caught

Devin Rhode
  • 23,026
  • 8
  • 58
  • 72
  • You know that `fn.1` is invalid synthax ? You need to use `fn[1]`. – HoLyVieR Aug 07 '11 at 03:09
  • So actually I think I've found out that what I want to do is use is the YUI available event, fired when "DOM respond to getElementById" http://developer.yahoo.com/yui/3/event/#onavailable Now I just have to make a more proficient doc.byId function that wraps dom calls in this YUI code functionality. However, I might lose getting an error, and thus not find out about code that has not yet run. – Devin Rhode Aug 16 '11 at 07:20

4 Answers4

60

I have mine working with window.onerror and it doesn't stop my javascript:

window.onerror = function(error, url, line) {
    controller.sendLog({acc:'error', data:'ERR:'+error+' URL:'+url+' L:'+line});
};

Note that controller.sendLog is a function that sends this data to a logging php.

Can be because you're causing some javascript error inside that function?

Sergi Ramón
  • 1,683
  • 1
  • 15
  • 14
  • I plugged your code into a plain page and found that execution stopped, are you in a special environment? Possibly extension development? – Devin Rhode Aug 07 '11 at 03:48
  • 4
    Well, it will stop execution of the current thread, because it hit an error, it's the normal behaviour in javascript. In the page i'm using this, i have lots of objects and events triggering here and there so if one breaks, that one stops executing but a new event triggering the same code work again. I think you can't avoid it stopping, the only way to do this is to use lots of try-catch blocks, and also, in a try-catch block the behaviour is the same, it stops executing the block and jump into the catch sentence. – Sergi Ramón Aug 07 '11 at 03:57
  • I accepted Sergi's answer since he showed use of url and line parameters that I didn't know about or use above – Devin Rhode Aug 07 '11 at 04:15
  • why do you check if line is greater than zero? – Devin Rhode Aug 07 '11 at 14:41
  • Some browsers doesn't report url and line number and I just doesn't wanted to log that errors, but it's only my particular case so i edited the answer to remove this. My application has lots of visits/day and this way i filter error log generation and focus on errors with more info than errors that i don't know where happen. – Sergi Ramón Aug 09 '11 at 01:20
  • add return true... `window.onerror = function(error, url, line) { controller.sendLog({acc:'error', data:'ERR:'+error+' URL:'+url+' L:'+line}); return true; }; ` – buycanna.io Sep 02 '18 at 06:35
  • 2
    Is this still the best way to capture all errors on the page? Could you also use `window.addEventListener("error", listener)`? – 1.21 gigawatts Mar 01 '19 at 02:29
  • @1.21gigawatts yes you can. And also add third parameter true. – atilkan Nov 18 '19 at 20:44
4

Sorry but try/catch will catch only code errors, never load error (if a file is missing or something that).

window.onerror / $(window).error is definitely the best solution.

2

When an exception is raised in most languages, execution of the current command stack is going to be stopped. So your global window.onerror approach works, but doesn't continue to execute code after a failure. I'm curious why you would expect a retry to work in the case that the original call fails? Maybe there's another way to optimize your application to avoid this.

One of the things I like to do is wrap any of my code in window.onerror function in a try catch block. In the catch statement (last resort) I will generally use an alert of some sort, just in case something goes catastrophically wrong. The idea here is that you don't want your error handling for the page to EVER end up causing another error to be launched.

Justin Beckwith
  • 7,686
  • 1
  • 33
  • 55
  • 1
    Good point about expecting the code to later succeed. I guess the main goal of this was to isolate chunks of code and get more errors mailed back. The reason I might expect it to work later is that, in extension development, sometimes content scripts may be running too early/fast, therefore waiting a bit would allow the page to load more and say load DOM elements that weren't previously loaded. – Devin Rhode Aug 07 '11 at 04:03
  • Other than that it may end up waiting for the network to become re-connected – Devin Rhode Aug 07 '11 at 04:07
-1

You can try also

Try...Catch Statement

try  
{  
  //Run your code here
}
catch(err)
{
  //Handle the errors here
}
  • 1
    This wont work with console errors, unless you overwrite the error function to throw the error as an exception instead: `console.error = error => { throw Error(error) };` though that's a rather bad practice. – Berry M. Nov 27 '17 at 08:26