Debugging Dojo Applications (2/10/2010)

Post on 09-May-2015

10.430 views 7 download

description

This was the presentation I gave at dojo.connect on February 10, 2010.

Transcript of Debugging Dojo Applications (2/10/2010)

Debugging Dojo Applicationsdojo.connect

February 10, 2010

Chris BarberCB1, INC.

http://www.cb1inc.com/

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

About Me

● Chris Barber

● Open source hacker

● Software consultant

● JavaScript, C++, PHP

● Dojo committer

● http://www.cb1inc.com/

● http://twitter.com/cb1kenobi

● http://slideshare.net/cb1kenobi

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

All Software Has Bugs

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Fixing Bugs Sucks

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Things You Could Be DoingInstead of Fixing Bugs

● Sleeping

● Reading a book

● Working out

● Enjoying a frosty brew

● Mowing the lawn

● Watching a movie

● Bowling

● Doing laundry

● Attending this presentation!

● Playing Bioshock 2

● Shopping for new shoes

● Getting your picture taken at those little booths at the mall

● Shoveling snow● Actually, this is worse

that fixing bugs

● Selling junk on eBay

● Buying junk on eBay

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Debugging Dojo& JavaScript

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Types of Bugs

● Syntax errors

● Runtime errors

● Logic errors

● Performance issues

● Bugs that other people committed into svn● Because our code is flawless

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Old School Debugging

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Old School Debugging

<form>

<textarea name="output"></textarea>

</form>

<script type="text/javascript">

alert("If you're reading this, it doesn't work.");

document.write("x should be 10, but for some reason it's " + x);

document.forms[0].output.value += "Loading external resource...\n";

document.forms[0].output.value += "Still loading...\n";

document.forms[0].output.value += "Hello?\n";

</script>

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Old School Debugging

● Write some code, reload, test, write some code, reload test, write some code, reload, test

● But if you write too much code● Comment out / remove huge chunks of code until

things work again

● View source● What exactly did the server send?

var quote_of_the_day = "Who said "debugging" ain't easy?";

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Old School Debugging

● Custom error handling awesomeness

window.onerror = function(msg, url, lineno){ alert("Thou art detects an error:\n" + "Message: " + msg + "\n" + "URL: " + url + "\n" + "Line #: " + lineno);};

function foo(){ var bar = "fail";

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Old School Debugging

● JavaScript console● Netscape 4, Mozilla, Firefox

● Internet Explorer● Generally sucked● Line # rarely correct● Crappy error messages

– "Object required"

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Old School Debugging

● Microsoft Script Debugger● Steaming pile

● Microsoft Script Editor

● Uses Visual Studio

● It's on your Office 2003 CDs

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Old School Debugging

● Venkman● Component of the Mozilla Suite● Also a Firefox extension● Sloooooooooooow

– Provided it didn't crash

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Not So Old School

● try/catch/throw● New in ECMAScript 3!

– Published Dec 1999

● Implemented by IE6/NS6try { if (something) { throw new Error("oh snap!"); }} catch (e) { alert(e);}

● Catches that suppressed errors● All over Dojo code base● If something is not working, check if it's being silently

being caught

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Advanced Tactics

● Proxy server

● Packet sniffing

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

JavaScript Bugs

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

JavaScript Bugs

● Syntax errors● Things that the cause the parser to hate life

function foo() {

foo(1 2);

dojo..isFunction(foo);

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

JavaScript Bugs

● Runtime Bugs● Undefined variables & methods● Unexpected results

foo(); // foo() undefined

var i = 10 + x; // x undefined

function bar() { return arguments.join(',');}

function baz(y) { return y * y;}

alert(baz(2)); // undefined!

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

JavaScript Bugs

● Variable scopes● Local vs global

● Naming● Case sentivity● Try to use unique

names to avoid accidentally overwriting

● Use meaningful names– Unless you need a little

more job security

● Watch out for reserved words!● Rhino (used by Dojo's

build tool) is very picky

break, case, catch, continue, default, delete, do, else, finally, for, function, if, in, instanceof, new, return, switch, this, throw, try, typeof, var, void, while, with

abstract, boolean, byte, char, class, const, debugger, double, enum, export, extends, final, float, goto, implements, import, int, interface, long, native, package, private, protected, public, short, static, super, synchronized, throws, transient, volatile

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

JavaScript Bugs

● Functions● Forgetting commas between arguments● Forgetting braces● Misspelling funtcion● Avoid resuing function names

function foo(){ alert("hello");}foo(); // alerts "world"

function foo(){ alert("world");}foo(); // alerts "world"

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

JSON Bugs

● Missing commas

● Hanging commas

● Confusing } and ]

● Not quoting names that contain special chars

var i = { firstName: "Chris" lastName: "Barber"};

var j = { firstName: "Chris", lastName: "Barber",};

var k = [ { "class": "JavaScript", "course #": 101 }, { "class": "C++", "course #": 102 };

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

JavaScript Engine Limits

● Max string length● Implementation dependent

● Max integer value● Really, really huge

● Max z-index● 2,147,483,647

● ...

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dojo

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

djConfig.isDebug

● Only useful in browsers that don't have a console● IE6/7● Firefox without Firebug● Old versions of Opera/Safari

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

djConfig.isDebug

● Automatically loads dojo._firebug.firebug

● Limited functionality● ReCSS, console, DOM viewer, Object viewer

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dojo.declare

● Used to define objects

● Careful what you initialize● Numbers, booleans, & strings are OK● Arrays & objects are a bad idea

– Use constructor() or postCreate() (if a dijit)dojo.declare("MyObj", null, { foo: [ "Hello" ], bar: null, constructor: function() { this.bar = ["baz"]; }});

var obj1 = new MyObj;var obj2 = new MyObj;

console.debug(obj1.foo); // outputs ["Hello"]console.debug(obj2.foo); // outputs ["Hello"]obj1.foo.push("world!");console.debug(obj1.foo); // outputs ["Hello","world!"]console.debug(obj2.foo); // outputs ["Hello","world!"]

obj1.bar.push("zap");console.debug(obj1.bar); // outputs ["baz","zap"]console.debug(obj2.bar); // outputs ["baz"]

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dojo.declare

● Extending objects● Invoking an inherited object's method

dojo.declare("MyObj", nullj, {

foo: function(){ alert("Hi from MyObj!"); }

});

dojo.declare("MyNewObj", MyObj, {

foo: function(){ alert("Hi from MyNewObj"); this.inherited(arguments); }

});

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dojo.data

● fetchItemByIdentity()● Make sure IDs are unique!

dojo.require("dojo.data.ItemFileReadStore");

var s = new dojo.data.ItemFileReadStore({ data: { identifier: "id", items: [ { id: "/foo", name: "foo", children: [ { id: "/foo/bar", name: "bar" } ] } ] } });

s.fetchItemByIdentity({ identity: "/foo", onItem: function(item){ console.info(item); }, onError: function(item){ console.error(item); }});

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Manipulating the DOM

● Wait until onload● dojo.addOnLoad() or dojo.ready() (new in 1.4)

● If you can't wait, use document.write()

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dojo.parser

● djConfig.parseOnLoad does not autoload dojo.parser

● Must dojo.require("dojo.parser")

● Can fire the parser manually● dojo.parser.parse()

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dojo.require()

● Build system is a little too smart● Uses regex to find requires

if(condition){ dojo.require("my.module");}

if(condition){ dojo["require"]("my.module");}

dojo.requireIf("my.module", condition);

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Closures & dojo.hitch()

// assume we're in an object's function...

dojo.forEach([1, 2, 3], this.foo); // Error!

var _t = this;dojo.forEach([1, 2, 3], function(n){ _t.foo(n) });

dojo.forEach([1, 2, 3], dojo.hitch(this, "foo"));

// does the same thing internally as dojo.hitch()dojo.forEach([1, 2, 3], "foo", this);

// dojo.connect does the same thingdojo.connect(myButton, "onclick", this, "foo");

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

file:/// issues

● Firefox 3 security causes issues● about:config

● security.fileuri.strict_origin_policy = false– http://kb.mozillazine.org/Security.fileuri.strict_origin_policy

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dojo.deferred

● Use errbacks

● dojo.xhr() returns a deferredfunction getData(i, n){ return dojo.xhrPost({ url: "/fetchData.php", postData: { id: i, name: n }, handleAs: "json" });}

var deferred = getData(123, "foo");deferred.addCallback(function(data){ console.log("Whoo!");});deferred.addErrback(function(error){ console.error("Oh noes!"); console.error(error);});

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dijit

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Widget Params

● Param must be defined before mixin

<div dojoType="MyObj" param1="abc" param2="def" param3="ghi"></div>

<script type="text/javascript">dojo.require("dijit._Widget");dojo.declare("MyObj", dijit._Widget, { param1: "", constructor: function(){ this.param2 = ""; }, postCreate: function(){ console.debug(this.param1); // abc console.debug(this.param2); // def console.debug(this.param3); // undefined }});</script>

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Template Errors

● 404 File not found

● No root node

● Invalid variables ${foo}● Variables must be defined before buildRendering()

– member variable

– initialize in constructor()

– initialize in postMixInProperties()

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Template Errors

● Say you want to speed up development

● Do a Dojo build of dojo, dijit, code that is good to go

● Your namespace is "foo" and you have a custom dialog that extends dijit.Dialog

● If using Dojo 1.3.2 or earlier, you MUST define templateString:null before your templatePath● Otherwise the dijit.Dialog's templateString overrides

your templatePath!

dojo.declare("foo.MyDialog", dijit.Dialog, { templateString: null, templatePath: dojo.moduleUrl("foo", "MyDialog.html")});

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Template Errors

● Not an issue with 1.4 and newer

● Just use templateString

● Use dojo.cache!● You can still use dojo.moduleUrl()

dojo.declare("foo.MyDialog", dijit.Dialog, { templateString: dojo.cache("foo", "MyDialog.html")});

// After build, template is inlined! Awesomedojo.declare("foo.MyDialog", dijit.Dialog, { templateString: dojo.cache("foo", "MyDialog.html", "<div>Hi from my dialog!</div>")});

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Template Errors

● Build system uses regex to inline templates

● Don't get cute

(function($){

$.declare("foo.MyDialog", dijit.Dialog, { templateString: $.cache("foo", "MyDialog.html") // NO! });

})(dojo);

(function($){

$.declare("foo.MyDialog", dijit.Dialog, { templateString: dojo.cache("foo", "MyDialog.html") // OK! });

})(dojo);

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Templates Caching Issues

● When not using a build, templates are loaded via XHR

● Templates may be cached by the browser● Definitely in Firefox

● Disable cache or empty cache after template changes

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

postCreate() vs startup()

● postCreate()● Template created● Can create new DOM nodes● Not every widget's postCreate() has been called yet!

● startup()● Called after a widget and its children have been created

and added to the page● All parent/child widgets created, postCreate() has been

called● Now you can start talking to other widgets :)

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Dijit Themes

● Live coding mistake #253● Forgetting to include the dijit theme's css file

<link rel="stylesheet" href="/path/to/dijit/themes/tundra/tundra.css" type="text/css"/>

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Dijit Themes

● Live coding mistake #254● Forgetting to add the theme name to the body class

<body class="tundra">

...

</body>

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Dijit Themes

● Only use what you need!

● Example: you only need a dijit.Calendar// mytundra.css

@import url("/path/to/dijit/themes/dijit.css");@import url("/path/to/dijit/themes/tundra/Common.css");@import url("/path/to/dijit/themes/tundra/form/Common.css");@import url("/path/to/dijit/themes/tundra/Calendar.css");

● Build system inlines only those files!<link rel="stylesheet" href="/path/to/mybuild/mytundra.css" type="text/css"/>

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

The Build System

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Build Profiles

● Define the prefixes you need● Build system copies each namespace● Don't need to specify "dojo" prefix

dependencies = {stripConsole: "normal",version: "1.4.1",cssOptimize: "comments",copyTests: false,optimize: "shrinksafe.keepLines",layerOptimize: "shrinksafe.keepLines",

layers: [{

name: "dojo.js",dependencies: [

"dijit.Dialog","dijit.layout.BorderContainer","dijit.layout.ContentPane"

]}

],

prefixes: [[ "dijit", "../dijit" ]

]}

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

ShrinkSafe

● optimize & layerOptimize● shrinksafe

– Awesome for production!

● shrinksafe.keepLines– Awesome for debugging!

● dojo.js & dojo.js.uncompressed.js● Use the uncompressed version for debugging

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Other Tricks!

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dojox.analytics

● Use it to send info back to the server● Dojo startup info● Window information● mouseover sampling● idle activity● console.* messages

<script type="text/javascript" src="/path/to/dojo.js" djConfig="sendMethod:'script', sendInterval:5000, analyticsUrl:'http://example.com/dojox/analytics/logger/dojoxAnalytics.php'"></script>

<script type="text/javascript">dojo.require("dojox.analytics");dojo.require("dojox.analytics.plugins.consoleMessages");dojo.require("dojox.analytics.plugins.dojo");dojo.require("dojox.analytics.plugins.idle");dojo.require("dojox.analytics.plugins.mouseClick");dojo.require("dojox.analytics.plugins.mouseOver");dojo.require("dojox.analytics.plugins.window");</script>

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

CSS Tricks

● Disable a style/property by changing the name to something invalid● x.myStyle{padding:10px;}

● Styling dojo.dnd.Avatars● Start a drag, then disable JavaScript● Use Firebug/ReCSS to finish styling

● Empty cache or disable cache to refresh background images

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Missing Images

● Create images and be notified if the image is 404

● dojox.image.Lightbox uses this technique

dojo.create("img", { id: "myimage", src: "/path/to/my/image.jpg", onerror: function(){ dojo.create("img", { id: "missingimage", src: "/path/to/missing/image.jpg" }, dojo.body()); }}, dojo.body());

// note: this code is untested... don't shoot me// if it doesn't work :)

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Performance

If it's slow, it's a bug

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Performance

● Use a Dojo build

● Only include the dijit css files you need

● Cache values that won't change● getViewport(), marginBox(), etc

● Destroy non-visible tab content

● Combine XHR payloads

● Use a profiler

● Write better code

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Performance

● Combine images into sprites● Additional sprite for repeat-x & repeat-y

● Enable gzip

● Use a CDN● Or multiple subdomains

● Put scripts at the bottom of the page

● Read Steve Souder's books!

● http://stevesouders.com/

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Testing

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Test Cases

● Write simple test cases● Individual html files to test a specific feature

● DOH: Dojo Objective Harness● Little chunks of code to test stuff

dojo.require("doh.runner");

dojo.addOnLoad(function(){ doh.register("myTest", [ function myFunction(){ var foo = []; foo.push(6); foo.push(1); foo.push(2); doh.is(foo.indexOf(1), 2); } ]); doh.run();});

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Testing Multiple Browsers

● Use a bunch of old computers

● Or join the modern web development revolution and use a virtual machine● Virtual Box● VMware Workstation● VMware Fusion● Parallels● IE6/IE7/IE8● FF2/FF3● Safari 3/4● Opera 9/10

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Testing Multiple Browsers

● Microsoft Virtual PC Disk Images

● http://tinyurl.com/osoomm

Disk Image Expires Size

IE6 + XP SP3 April 1, 2010 753.8MB

IE7 + XP SP3 April 1, 2010 813.1MB

IE8 + XP SP3 April 1, 2010 812.9MB

IE7 + Vista 120 days after first run 700.0MB, 700.0MB, 590.5MB

IE8 + Vista 120 days after first run 50.6MB, 700.0MB, 700.0MB, 687.9MB

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Tools

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Firefox Extensions

● Lori – Life-of-request info (page load times)

● Tamper Data● Dated, but can still be useful

● Web Developer Toolbar

● Firebug

● Firecookie

● Yslow

● Many, many, many, many more...

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Firebug

● http://www.getfirebug.com/

● console.log(), console.debug(), console.info(), console.warn(), console.error()● Use "," instead of "+": console.debug("x =", x);

● Console

● Debugger

● Profiler

● more...

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Firebug Lite

● http://getfirebug.com/firebuglite

● Bookmarklet

● More featureful than Dojo's FBL

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Webkit Web Inspector

● Chrome/Safari/Epiphany/Titanium

● Enable in Safari from command line:– defaults write com.apple.Safari IncludeDebugMenu 1

● Console

● Debugger

● Profiler

● more...

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

IE Developer Toolbar

● IE6/IE7

● DOM viewer

● Modify CSS

● Clear cache

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Internet Explorer 8

● Integrated into IE8!

● Console

● Debugger

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

IDEs With JavaScript Debuggers

● Netbeans● http://netbeans.org/kb/67/web/js-debugger-ug.html

● Firefox & IE

● Aptana Studio● http://www.aptana.org/studio

● Eclipse + Fireclipse● http://www.almaden.ibm.com/u/bartonjj/fireclipse

● Still active?

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

dair

● Dojo Extensions for Adobe AIR

● http://o.sitepen.com/labs/dair/

● Debug console

● Command line logger

● File logger

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Resources

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Getting Help

● API Docs

● http://api.dojotoolkit.org/

● http://docs.dojocampus.org/

● IRC● #dojo on irc.freenode.net

● dojo-interest Mailing List● http://mail.dojotoolkit.org/mailman/listinfo/dojo-interest

● Dojo's source code

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Getting Help

CB1, INC

http://www.cb1inc.com/

Dojo ConsultingWeb Applications

dojo.connect | 2.10.2010 | Chris Barber | CB1, INC. | http://www.cb1inc.com/

Thanks!

Questions?

http://slideshare.net/cb1kenobi http://twitter.com/cb1kenobi