With the rise of cell units, net improvement and debugging is extra advanced than ever. We now have extra browsers and platforms to assist. We now have extra display sizes and resolutions. And we’re constructing in-browser functions as a substitute of the flat, brochure-ware websites of yore.
Article Continues Under
Fortunately, we even have higher instruments. The JavaScript console is a typical characteristic of most main browsers. Each JavaScript and the HTML DOM provide native error dealing with. We even have providers and functions that assist us remotely debug our websites.
On this article I’ll cowl error thowing and dealing with, code injection, and cell debugging. For extra on debugging, see Hallvord R.M. Steen and Chris Mills’ 2009 article, Superior Debugging With JavaScript.
Throwing and catching errors#section2
JavaScript helps you to report and deal with errors by a mix of the throw
and strive
…catch
statements, and the error
object.
Error throwing is helpful for catching runtime errors—say, a operate that has incorrect arguments. Within the instance under, add()
accepts two parameters. It’s going to throw an error if the equipped arguments are null, or are neither a quantity nor a numeric string. (Line wraps marked » —Ed.)
operate add(x,y){ if( isNaN(x) || isNaN(y) ){ throw new Error("Hey, I want two numbers so as to add!"); } else { // guarantee we're including numbers not concatenating » numeric strings. return (x * 1) + (y * 1); } }
Let’s strive invoking add()
utilizing invalid arguments. We’ll then catch the error thrown through the use of a strive
…catch
block and output it to the console:
var a;strive{ a = add(9); } catch(e) { console.error( e.message ); }
Fig 1: The Dragonfly console error
In Opera Dragonfly (above), we see the error message and its corresponding line quantity, relative to the script. Remember in these examples we’re embedding JavaScript inside our HTML web page.
Fig. 2: The Firebug error console
Firebug additionally consists of the thrown error message and line quantity, however relative
to the doc.
All error objects have three commonplace properties:
constructor
: returns a reference to the Error operate that created an occasion’s prototype,message
: the message thrown—the message you handed as an argument, andidentify
: the kind of error—oftenerror
, until you employ a extra particular kind.
As of this writing, error objects in Firefox additionally embody two non-standard properties: fileName
and lineNumber
. Web Explorer consists of two non-standard properties of its personal: description
(which works equally to message
) and quantity
(which outputs the road quantity).
The stack
property additionally isn’t commonplace, but it surely is kind of supported by the newest variations of Chrome, Firefox, and Opera. It traces the order of operate calls, with corresponding line numbers and arguments. Let’s modify our instance to alert the stack
as a substitute:
var a;strive{ a = add(9); } catch(e) { alert( e.stack ); }
Fig 3: The stack property revealing the throw error within the code
The stack
property reveals the place within the code throw Error
exists (on this case, line seven) and on which line the error was triggered (on this case, line 15).
You don’t need to throw an error object. You might, for instance, throw a message: throw “The worth of x or y is NaN.”
Throwing an error, nonetheless, affords richer info in most browsers.
Utilizing strive
…catch
can, nonetheless, have a unfavourable impact on script minification and efficiency. Whereas useful for debugging, your production-ready code ought to use strive
…catch
sparingly, if in any respect.
Dealing with errors utilizing the window.onerror
occasion#section3
The Doc Object Mannequin additionally affords a mechanism for capturing errors: the window.onerror
occasion. Not like strive
…catch
, you may set an occasion handler for window.onerror
that captures errors you don’t throw. This will occur in case you attempt to invoke an undefined operate or entry an undefined variable.
When the window.onerror
occasion is fired, the browser will verify to see whether or not a handler operate is offered. If one isn’t out there, the browser will reveal the error to the consumer. If one is offered, the handler operate receives three arguments:
- the error message,
- the URL by which the error was raised, and
- the road quantity the place the error occured.
You possibly can entry these arguments in one among two methods:
- through the use of the
arguments
object that’s native to and domestically out there to all JavaScript capabilities; or - through the use of named parameters.
Within the instance under, we’ll use arguments
. For readability, although, it’s best to use named parameters:
window.onerror = operate(){ alert(arguments[0] +'n'+arguments[1]+'n'+arguments[2]); }init(); // undefined and triggers error occasion.
Fig 4: What our error appears to be like like as an alert in Web Explorer 9
Right here init()
has not but been outlined. In consequence, the onerror
occasion can be fired in supporting browsers.
Now the caveat: assist for window.onerror
is proscribed. Chrome 10+ and Firefox (together with cell) assist it. Web Explorer helps it, however actually useful error messages are solely out there in model 9+. Whereas the newest builds of WebKit assist window.onerror
, latest variations of Safari and barely older variations of Android WebKit don’t. Opera additionally lacks assist. Anticipate that to vary because the HTML5 specification evolves and browser distributors standardize their implementations.
Modify JavaScript on the fly utilizing the command line interface#section4
One of many extra highly effective options out there in immediately’s debugging instruments is the JavaScript console. It’s virtually a command line for JavaScript. With it, you may dump information or inject JavaScript to look at why your code has gone rogue.
Launching the JavaScript Console#section5
- In Chrome: View > Developer > JavaScript console
- In Safari: Develop > Present Internet Inspector
- In Web Explorer 8 & 9: Instruments > Developer Instruments (or use the F12 key)
- In Opera: Discover Dragonfly beneath Instruments > Superior (Mac OS X) or Thực đơn > Web page > Developer Instruments (Home windows, Linux)
Firefox is a particular case. For years, builders have used the Firebug extension. Firefox 4, nonetheless, added a local console (Instruments > Internet Console or Thực đơn > Internet Developer > Internet Console).
Firebug totally helps the Console API, and has extra sturdy CSS debugging options. I like to recommend putting in it, although the Internet Console is a succesful software for fundamental wants.
I’m utilizing Opera’s debugging software Dragonfly within the examples under (sure, I work for Opera). These examples, nonetheless, work equally in Chrome, Safari, Firefox, Firebug, and Web Explorer.
Let’s take one other take a look at the code from our earlier examples. We’re going so as to add a brand new line—var a = doc.querySelector(’#end result’);
—one which assumes a component with an id worth of “end result.”
A fast observe in regards to the querySelector()
technique: it and querySelectorAll()
are a part of the DOM selectors API. querySelector()
returns the primary ingredient matching the required CSS selector. Each strategies are supported by the newest variations of most browsers. You might additionally use doc.getElementById(‘end result’)
, however doc.querySelector()
is extra environment friendly:
operate add(x,y){ if( isNaN(x) || isNaN(y) ){ throw new Error("Hey, I want two numbers so as to add!"); } else { // guarantee we're including numbers not concatenating numeric strings. return (x * 1) + (y * 1); } }var a = doc.getElementById('end result');strive{ a.innerHTML = add(9); } catch(e) { console.error(e.message); }
Fig 5: The Dragonfly console
Our thrown error remains to be written to the console. However let’s inject some JavaScript that runs accurately. We’ll enter a.innerHTML = add(21.2, 40);
in our console:
Fig 6: The Dragonfly console with injected code
As you may see, we have now overwritten the innerHTML
worth of a
:
Fig 7: A web page with injected code
Now let’s change the worth of a
totally. Enter a = doc.querySelector(‘h1’); a.innerHTML = add(45,2);
within the console:
Fig 8: Altering code within the console
You’ll see that 47 is written to the console, and it is usually the brand new innerHTML
of our h1
ingredient:
Fig 9: Modifying the DOM
Now, we are able to even redefine our add()
operate. Let’s make add()
return the product of two arguments after which replace the h1
. Enter operate add(){ return arguments[0] * arguments[1]; }
within the console, adopted by a.innerHTML = add(9,9);
:
Fig 10: Overwriting a operate utilizing the JavaScript console
The brand new innerHTML
for our h1
ingredient is now 81, the results of our redefined add
operate:
Fig 11: The outcomes of overwriting a operate
The JavaScript console affords a robust software for understanding how your code works. It’s much more highly effective when used with a cell gadget.
Distant debugging for cell#section6
Debugging code on a cell gadget remains to be one among our largest ache factors. However, once more: now we have now instruments. Opera Dragonfly and its distant debug characteristic supplies builders a technique to debug cell websites from their desktop. WebKit not too long ago added distant debugging to its core and Google Chrome has already folded it into its developer instruments.
Impartial builders provide related merchandise for different browsers. These embody Bugaboo, an iOS app for Safari-based debugging; JS Console which is offered on the net or as an iOS app; and Weinre for WebKit-based browsers.
Let’s take a look at two: Dragonfly distant debug and JSConsole.
Distant debugging with Opera Dragonfly#section7
Dragonfly’s robust go well with is that you could debug CSS or headers (see the Community tab) along with JavaScript. However it does require putting in Opera in your desktop and Opera Cell in your gadget.
Each units must be linked to the identical native community. Additionally, you will want the IP deal with of the machine operating Dragonfly. Then full the next steps:
- open Dragonfly from the Instruments > Superior (Mac OS X) or Web page > Developer Instruments (Home windows, Linux) menus,
- click on the Distant Debug button ,
-
regulate the port quantity in case you’d like, or use the default and click on “Apply, ”
Fig 12: The distant debugging panel in Dragonfly
-
open Opera Cell in your goal gadget, and enter
opera:debug
within the deal with bar, andFig 13: Opera Cell debug console
-
enter the IP deal with and port variety of the host machine and click on “Connec,t” and
Fig 14: The IP and Port fields of the opera:debug console
- navigate to the URL of the HTML web page you want to debug in your gadget.
Fig 15: An alert on Opera Cell
Dragonfly on the host machine will load the distant web page. You possibly can then work together with the web page as if it was in your desktop. You will note the outcomes on the gadget. For instance, in case you enter alert( add(8,923) )
within the host console, the alert seems on the cell gadget display.
Distant debugging with JSConsole#section8
To make use of JSConsole:
- go to the location and enter
:hear
on the immediate, - add the returned script tag to the doc you want to debug, and
- open the doc in your cell gadget.
Distant console statements will seem within the JSConsole window (you do want to make use of console.log()
somewhat than console.error()
or console.warn()
). You can too ship code from the JSConsole window to your gadget. On this case, alert( add(6,3) );
.
Fig 16: Sending a command utilizing JSConsole.com
Distant error logging#section9
Within the examples above, we’re logging to the console, or launching an alert field. What in case you logged your errors to a server-side script as a substitute?
Think about the next code that makes use of XMLHttpRequest()
. In it, we’re :
operate sendError(){ var o, xhr, information, msg = {}, argtype = typeof( arguments[0] ); // whether it is an error object, simply use it. if( argtype === 'object' ){ msg = arguments[0]; } // if it's a string, verify whether or not we have now 3 arguments… else if( argtype === 'string') { // if we have now 3 arguments, assume that is an onerror occasion. if( arguments.size == 3 ){ msg.message = arguments[0]; msg.fileName = arguments[1]; msg.lineNumber = arguments[2]; } // in any other case, put up the primary argument else { msg.message = arguments[0]; } } // embody the consumer agent msg.userAgent = navigator.userAgent; // convert to JSON string information="error="+JSON.stringify(msg); // construct the XHR request xhr = new XMLHttpRequest(); xhr.open("POST",'./logger/'); xhr.setRequestHeader("Content material-type", "utility/x-www- » form-urlencoded"); xhr.ship( information ); // disguise error message from consumer in supporting browsers return true; }
Right here we’re posting our error messages to a script that logs them in a flat file utilizing PHP:
<?php// decode the JSON object. $error = json_decode( $_POST['error'], true ); $file = fopen('log.txt','a'); fwrite($file, print_r( $error, true) ); fclose($file);?>
Now the disclaimer: please for the love of tequila, don’t let this script write to a world-readable listing. The potential for code injection on account of spoofed headers or variables just isn’t well worth the danger. Logging scripts like this could solely be used throughout improvement, and by no means on manufacturing servers.
Conclusion#section10
As the net has developed, so have our instruments. Code injection, error throwing and catching, and distant debugging providers are all serving to us ship higher, much less buggy apps.