Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle Javascript errors when also using jQuery?

My Situation

Hi, Im relatively new to Javascript so my question could be really easy. Im developing multiple webapps for my company. One problem I run in regularly are Javascript-errors. I know how to handly them using try/catch.

What I want to do

I want to either write a logfile on the server or give the user something they can send me without any knowledge of debugging. This means, the user has to be informed that an error occurred in both cases.

What I already did

One idea I had was using try catch and using code I found here: https://stackoverflow.com/a/6055620/3581748 to give the user the possibility to send me the stacktrace.

Example:

<button id="demo" onClick="errorHandling()">Produce error</button>
<script>
function errorHandling() {
    try {
        document.getElementById("somethingNotExisting").value * 2;
    } catch (_err) {
        window.prompt("Copy to clipboard: Ctrl+C, Enter", _err.stack);
    }
}
</script>

Or here: https://jsfiddle.net/n79xv6nt/

Which works most times.

The Problem

I sometimes embed scriptfiles in my "main"-page using jQuery. Example:

<div id="forScript"></div>
<script>
    $("#forScript").load('scripts/additionalScript.php');
</script>

If I use the above code (the one below "What I already did"). I dont get a stacktrace that tells me where the error occured. It instead points to a jQuery-file. The Google Chrome Console shows the real stacktrace. Another problem is, how do I get to the file after I got the linenumber? In my IDE the lines are different because there is php in between.

My Question

Is it possible to get a good errormessage for this case? (preferably without having to throw an error myself) How can I access the additional script and see the same linenumbers that chrome is seeing? And how would you notify the user/log the error?

like image 729
Simon Balling Avatar asked Nov 17 '15 09:11

Simon Balling


Video Answer


1 Answers

Information

Ok, first of all have a look at this link: http://tobyho.com/2011/06/08/the-javascript-stacktrace-blog/. It has lots of information on the topic regarding different browsers and different ways of executing javascript. Each browser and execution method gives a different covering of possibilities.

For example in IE, most methods do not work, and you can only get a line-number with sometimes the correct file.

Another method that works in most browsers but only provides you with the linenumber and file is:

window.onerror = function(message, fileURL, lineNumber){
  log(message + ': ' + fileURL + ': ' + lineNumber)
}

Solution 1: DIY

Your solution is the DIY (Do it Yourself) Stacktrace. With the DIY Stacktrace the trace you get is always correct. There are some disadvantages though that you need to consider:

  1. It will not get you file locations/line numbers.
  2. It does not work with thrown errors - either implicitly or explicitly - because the building of the stacktrace needs to be explicited done as its own statement, say, printStackTrace, for example. So, you cannot have a stacktrace and an error thrown - you cannot have your cake and eat it too.

code:

function printStackTrace() {
  var callstack = [];
  var isCallstackPopulated = false;
  try {
    i.dont.exist+=0; //doesn't exist- that's the point
  } catch(e) {
    if (e.stack) { //Firefox
      var lines = e.stack.split('\n');
      for (var i=0, len=lines.length; i&lt;len; i++) {
        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
          callstack.push(lines[i]);
        }
      }
      //Remove call to printStackTrace()
      callstack.shift();
      isCallstackPopulated = true;
    }
    else if (window.opera &amp;&amp; e.message) { //Opera
      var lines = e.message.split('\n');
      for (var i=0, len=lines.length; i&lt;len; i++) {
        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
          var entry = lines[i];
          //Append next line also since it has the file info
          if (lines[i+1]) {
            entry += ' at ' + lines[i+1];
            i++;
          }
          callstack.push(entry);
        }
      }
      //Remove call to printStackTrace()
      callstack.shift();
      isCallstackPopulated = true;
    }
  }
  if (!isCallstackPopulated) { //IE and Safari
    var currentFunction = arguments.callee.caller;
    while (currentFunction) {
      var fn = currentFunction.toString();
      var fname = fn.substring(fn.indexOf(&amp;quot;function&amp;quot;) + 8, fn.indexOf('')) || 'anonymous';
      callstack.push(fname);
      currentFunction = currentFunction.caller;
    }
  }
  output(callstack);
}

function output(arr) {
  //Optput however you want
  alert(arr.join('\n\n'));
}

Solution 2: Getting line X from js or php file.

Using the methods you use already, and the one provided in the Information section of this answer, in most cases you can get the linenumber and filename of where the error occurs.
You can use javascript to get the actual line of code from a file so you know where the error occurs. You can do that using ajax (jQuery $.get for example). See the below code:

var LineNumber = 0; //your line number from error here.
$.ajax({
    type: 'GET',
    url: 'YOURFILE',
    success: function (file_html) {
        // success
        console.log('success : ' + file_html);
        var file_content = "" + file_html //implicit convert to string
        var lines = file_content.split("\n");

        alert(lines[LineNumber]);

    }
});  
like image 193
Bas van Stein Avatar answered Nov 15 '22 15:11

Bas van Stein