Showing posts with label Lazy function definition. Show all posts
Showing posts with label Lazy function definition. Show all posts

Saturday, 24 March 2012

Logging and Suppressing JavaScript errors

Logging JavaScript errors to a file by overwriting the window.onerror method

Sometimes you may have intermittent JavaScript errors that you cannot re-produce or maybe you just want to be able to log JavaScript errors for later viewing. Or maybe you just want to suppress them so that end users don't see them.

By using the useful and also dangerous feature of being able to overwrite core JavaScript functions and objects you can utilise this to your advantage by overwriting the window.onerror method.

The window.onerror method takes 3 parameters which are:

  • message : the error message
  • url: the URL of the file that raised the error message
  • line: the line number that the error occurred on.


Therefore it is very easy to create your own window.onerror function to take these values and then make an AJAX call to a server side page which logs the JavaScript error details to a file or database or even sends an email.

Also by overwriting the window.onerror function we can suppress JavaScript errors if we chose to.

Maybe if we are debugging a script and don't want the error console constantly filled up or maybe some of our users are still using Windows 98 and use IE 4.

If we are using unobtrusive JavaScript that builds layer upon layer of functionality starting with the lowest common denominator e.g HTML, then adding JavaScript functionality if they have it, Flash if they have it and so on then we may want to just suppress these JavaScript errors in old browsers.

To suppress a JavaScript error you just need to return true.

This example uses jQuery seeing that is so popular but any AJAX library can be used. The point is that you are taking the error parameters and logging them somewhere useful.

I have used a little JavaScript wrapper object to set some system properties like a config object to define whether error logging is on or off and whether or not to suppress errors in older browsers. 

The code to define which browsers to suppress in can be left to you but I have done a simple test for document.getElementById which means browsers like IE 4 and NN4 won't get errors raised.


// Log JS errors to a file - file is overwritten each day only use when debugging a particular page/site

// Set up our global config options to decide whether to log JavaScript errors and whether or not to suppress them. A simple false/true could suffice but we might want to test for old browsers or certain features. If the browser doesn't support document.getElementById it's a pretty old browser!
GlobalSettings = {
 SystemName : "Strictly-Software",
 Version : 2.0.1,
 LogJSErrors : true,
 SuppressJSErrors : (document.getElementById) ? false : true
}

// override the onerror object
window.onerror = function(msg, url, line)
{   
 // does our global system want to log errors - this could be a Client or Serverside setting
 if (GlobalSettings.LogJSErrors)
 {  
                // using JQuery to post a GET request to a page that logs the error details
  $.get("logJSError.php", { message: msg, errorlocation: url, lineno: line } );
 }
 

 // do we still raise the error or for old browsers which might have a lot of errors do we try and supresss them? Use our global config options again.
 if(GlobalSettings.SuppressJSErrors){  
  // return true to suppress the error so its not raised to the console.
  return true;
 }else{
  // return false to raise the error to the console.
  return false;
 } 
}

Then all you need is to define your server side page logJSError.php (or whatever language you are using) to collect the error data from the request and do whatever you want with it e.g log it somewhere for later viewing.

Remember whilst being able to overwrite functions that already exist is good in certain situations like this and the Lazy Function scenario but it can also cause you severe debugging nightmares like the one I discovered when using the common addEvent naming convention for cross browser adding of events.

Therefore be careful especially when overwriting core JavaScript features but also use them to your advantage when possible.


Saturday, 26 September 2009

Using Lazy Function Definition

Redefining functions in a good way

Javascript is a language that lets you overwrite existing objects and functions very easily. This can be a curse when it happens without you realising which is why namespaces are always a good idea when you are developing a site that makes use of numerous scripts, frameworks and add-ons. I even blogged the other day about some trouble I had when a helper function was overwritten by another library which caused some issues: http://blog.strictly-software.com/2009/09/trouble-with-this-keyword-and.html

However one of the ways that overwriting functions can be good for your coding is when the function contains a computation or test that only needs to be run the first time the function is called. You can run this test and then overwrite the function to return the value depending on the computation.


A Debugger example

A lot of times when I am quickly testing some code without including extra scripts I want to be able to output debug messages to help with the testing. I usually want to output to the console if available but some browsers don't allow the console to be locked to the window or with IE and sometimes FireFox / Firebug I may not want to use their console due to issues with speed and locking. In these cases I just create a DIV at the bottom of the screen to output messages to with some HTML like this:
<div style="width:98%;overflow:auto;background:white;height:200px;color:black;text-align:left;border:1px solid black;" id="output"></div>

I then use a function called ShowDebug to output the messages. Now I have seen similar code on the web and have written some myself that would use the following logic within the ShowDebug function to decide whether to output to the console or the DIV.
var logToDiv = false;
var c = 1;
ShowDebug = function(m){
if (typeof(window.console)=="undefined" || logToDiv){
var msg = c + ": " + m + "<br />";
G('output').innerHTML=G('output').innerHTML+msg;
c++;
}else{
console.log(m)
}
}

However as you can see this would be quite expensive as for every call to ShowDebug the same conditional test is being carried out. If you are making thousands of calls to this function then this is quite an overhead and one that can be removed.


The better way - Lazy Function Definition

The better way is to run the conditional test for the console or DIV on the first call to ShowDebug and then overwrite the ShowDebug function to use the appropriate method from then on. All subsequent calls will either just output to the console or to the DIV.
ShowDebug = function(m){
var logToDiv = false;
if (typeof(window.console)=="undefined" || logToDiv){
var c = 1;
ShowDebug = function(m){
var msg = c + ": " + m + "<br />";
G('output').innerHTML=G('output').innerHTML+msg;
c++;
}
}else{
ShowDebug = function(m){
console.log(m)
}
}
ShowDebug(m);
}

This is called Lazy Function Definition and although this is a very basic example it shows you the possibilities of its use to avoid expensive mathematical computations or checks for non-existing properties or values on each function call.

Here are some articles that go into this concept in more depth: