Sunteți pe pagina 1din 82

en B

s ith ra alb G

Musings on the State of Ajax


ben@ajaxian.com

Who is Ben Galbraith?

Founder, Ajaxian.com User interface consultant (Ajax / Swing) Frequent technical speaker / author

What is he doing lately?

Does anyone here not know what Ajax is?

Ajax: A New Approach to Web Applications


by Jesse James Garrett February 18, 2005

Google Suggest and Google Maps are two examples of a new approach to web applications that we at Adaptive Path have been calling Ajax. The name is shorthand for Asynchronous JavaScript + XML, and it represents a fundamental shift in whats possible on the Web.

Ajax: A New Approach to Web Applications


by Jesse James Garrett February 18, 2005

Would you like to see how it works?

Ajax == DHTML
Key Ajax ingredient: XMLHttpRequest (a.k.a. XMLHTTP) Introduced by MS in 1997 Copied by Mozilla 1.0 in 2002 innerHTML helps a great deal DOM API snobs notwithstanding

XMLHttpRequest
Method
open("method", "URL"[, asyncFlag[, "userName"[, "password"]]]) send(content) abort() getAllResponseHeaders() getResponseHeader(header) setRequestHeader(label, value)

Description Setup the request (note the asyncFlag parameter) Send the request; content is request body (i.e. POST data) Stop a request in process Return a hash of header/value pairs Retrieve a response header value Set header (overriding browser headers allowed)

XMLHttpRequest
Property
onreadystatechange

Description Reference to callback function Current state of XHR; one of: 0 = uninitialized 1 = loading 2 = loaded 3 = interactive 4= complete Text value of response body DOM tree of response body Numeric status code (e.g., 200, 404) Text status message corresponding to status code

readyState

responseText

responseXML status statusText

Three Main Ajaxian Architectures


Return Data (JSON / XML) Return HTML (responseText + innerHTML) Return JavaScript (eval)

The Ajax Innovators

The Ajax Innovators

The Ajax Innovators

The Ajax Innovators

Ajax is the victory of the pragmatists over the purists*


* they want a rematch

Ajax is about more than sending data back and forth

Ajax has become a catch-all buzzword for highly interactive websites


(get over it)

And the biggest surprise?

JavaScript doesnt suck, after all


(but still dont hire people who call it Java on their CV)

What about Flash? Is Flash Ajax?

Web / Ajax Myths


Ajax is hard Rich effects (and widgets) are best left to
desktop applications

Cross-browser differences are too painful

Off-line mode isnt possible Client-side validation is a pain

Ajax vs. Desktop Apps


Ajax Advantages
Ease of development model Ease of deployment Mash-ups Separation of concerns Hackability (e.g., Greasemonkey)

Desktop Advantages
Much faster than JavaScript Advanced graphical capabilities Tight integration with OS Mature UI toolkits Lack of hackability (e.g., security)

Ajax vs. Desktop Apps: UI Richness


Web 1.0 Swing/WinForms

Ajax Flash Avalon / Cocoa

Premier Ajax Example

Avalon Example

What can Ajax do for you?

Increase Participation

Richer Interactivity

Portals That Dont Stink

Forums That Dont Stink

Rich, client-side validation

Ajaxian Frameworks
RAD High-level Tools
(TIBCO, TIBET)

Server-side Web Frameworks


(ASP.NET + Atlas, JSF + ICEfaces, Tapestry, Rails)

UI Toolkits
(Dojo, Script.aculo.us, Moo.fx)

Remoting Toolkits
(Prototype, Dojo, Mochikit)

JavaScript Tools and Utilities

XMLHttpRequest

IFrame

...

Ajaxian Frameworks
RAD High-level Tools
(TIBCO, TIBET)

Server-side Web Frameworks


(ASP.NET + Atlas, JSF + ICEfaces, Tapestry, Rails)

Client-side Frameworks (Effects + Remoting)


(Dojo, Prototype + Script.aculo.us, jQuery, Moo.fx + other Moo tools)

JavaScript Tools and Utilities

XMLHttpRequest

IFrame

...

Key Architectural Issues


Server push Cross-domain scripting Mash-ups

Server Push
Problem: How to push data from server to client? Two solutions: Polling (e.g., email) Keep-alive Some call this Comet

Comet
Coined by the Dojo team (Alex Russell et
al.)

Beware the two connection limit Java server implementations: DWR Jetty

Cross-Domain Scripting
Problem: Page may not request resources outside
of originating domain

Solution: Proxy server Browser hacks

Proxy Server
May be more useful than you would think Allows you to: Track what your users are doing Control access to third-party services
(when you care)

Avoid hackish nature of other solutions

Browser Hacks
Dozens of ways to do cross-site scripting
(XSS); see http://ha.ckers.org/xss.html

Most popular: Dynamic script tag IFRAME (built-in to Dojo) Flash

TIBCO GI

Ajaxian Frameworks
Prototype
DWR
jQuery MochiKit

Script.aculo.us
moo tools
Rico GWT

Dojo

Yahoo! UI

and a thousand other frameworks...

11.25%

22.50%

33.75%

45.00%

0%
45%

Prototype
34%

Script.aculo.us
25%

Hand-rolled
18%

Dojo
12%

DWR
11%

Moo.fx
8%

jQuery
5% 5% 4% 4% 3% 1%

YUI Rico Atlas MochiKit GWT qooxdoo

Ajaxian Framework Survey

Ajaxian Frameworks
A Brief Introduction to Some of My Favorites

Prototype

Prototype takes the pain out of common Ajax tasks

Tightly integrated with Ruby-on-Rails Can be used with any backend

Completely undocumented (by its creators)

Various third-party websites provide varying levels of documentation

http://www.sergiopereira.com/articles/ prototype.js.html

Prototype Contents

Prototype provides three levels of functionality:

Utility functions (globally scoped) Custom objects Extended properties on JavaScript native and hosted objects

Some folks consider this a no-no

Basic Utilities

Prototype contains a number of tools that take the pain out of DOM manipulation:

$() function - shortcut for Document.getElementById

Can take multiple arguments and will return all matching elements

$F() function - returns the value of any form control

Pass it either the element id or the element object

More Basic Utilities

Try.these() function - takes functions as arguments and returns the return value of the rst function that doesnt throw an exception.
var returnValue; for (var i = 0; i < arguments.length; i++) { var lambda = arguments[i]; try { returnValue = lambda(); break; } catch (e) {} } return returnValue;

Ajax Helpers

The Ajax object provides a number of helpful Ajaxrelated functionality At its simplest, can be used to obtain XHR in a crossbrowser way: var xhr = Ajax.getTransport()

Ajax Helpers

Implementation of Ajax.getTransport():
var Ajax = { getTransport: function() { return Try.these( function() { return new ActiveXObject('Msxml2.XMLHTTP') }, function() { return new ActiveXObject('Microsoft.XMLHTTP') }, function() {return new XMLHttpRequest()} ) || false; } }

Ajax Helpers

Provides higher-level functionality for performing Ajax operations:

Ajax.Request() object - takes a url and an options object as arguments

Performs an XHR request Options argument species XHR conguration parameters and one or more callbacks

Ajax Helpers

Options object:

Created using anonymous object creation syntax:


{ method: get, onComplete: callBackRef }

Supported properties:

method, asynchronous (true/false), parameters, postBody, requestHeaders (hash), onLoading, onLoaded, onInteractive, onComplete

Ajax.Request Example
var request = new Ajax.Request( /someUrl, { method: get, onComplete; myCallBack } ); function myCallBack(xhr) { $(someElementId).innerHTML = xhr.responseText; }

Ajax Helpers

Ajax.Updater() object - takes an element id, a url and an options object as arguments

Executes XHR and displays response as contents (innerHTML) of specied element First argument can be an anonymous object with a success property and a failure property set to the ids of elements Executes JavaScripts contained in response HTML

Ajax.Updater Example
var request = new Ajax.Updater( someElementId, /someUrl, { method: get, parameters: value=foo } );

Ajax Helpers

Ajax.PeriodicalUpdater() object - takes an element id, a url and an options object as arguments

Same behavior as Ajax.Updater() but continuously performs request every 2 seconds frequency property on options object controls the update frequency in seconds stop() function halts the updating; start() function can restart it

JavaScript Extensions

Number.toColorPart() function - converts decimal to hex String.stripTags() function - removes any tags from the string String.escapeHTML(), String.unescapeHTML() Document.getElementsByClassName()

Custom Objects

Element object makes manipulating elements much easier:

Element.show(), Element.hide(), Element.toggle() take an unlimited number of element id or references

Show/hide based on CSS display attribute

Element.remove() - nukes element by id or reference from the DOM

Custom Objects

Element.addClassName(), Element.hasClassName(), Element.removeClassName() - take two arguments: element id (or reference) and the class name Field.clear() - takes an unlimited number of form element ids or references and clears their values Field.present() - takes form elements ids or references; returns true if all are non-blank Field.focus(), Field.select(), Field.activate() - takes an element id/ref, and focuses, selects, or focuses/selects

Custom Objects

Form.serialize() - takes form element id/ref; returns the HTTP query string Form.getElements() - takes form element id/ref; returns array with all form elements Form.disable(), Form.enable(), Form.focusFirstElement(), Form.reset() - take form element id/ref

Prototype and Ruby

Prototype implements methods and ideas familiar to a Ruby programmer

Collection inspection and manipulation methods embedded directly on the collection object itself

Closure-centric syntax

each

var Numbers = [0, 1, 4, 5, 98, 32, 12, 9]; Traditional Iteration:
for (var i = 0; i < Numbers.length; i++) { alert(Numbers[i]); }

New each style:


Numbers.each(function(num) { alert(num); });

collect
var Products = [ {name: 'Basecamp', company: '37signals', type: 'Project Management'}, {name: 'Shopify', company: 'JadedPixel', type: 'E-Commerce'}, {name: 'Mint', company: 'Shaun Inman', type: 'Statistics'} ];

collect: iterate over an Array and return the results as a new array:
return Products.collect(function(product) { return product.company; }).join(', ');

Result: 37signals, JadedPixel, Shaun Inman

include
var Artists = ['Air', 'Bjrk', 'Arturo Sandoval', 'Orb'];

include: check if a value is included in an array (returns boolean)


return Artists.include(Depeche Mode);

Result: false

And Much More...

Prototype also contains utilities for inserting values into existing HTML content, event handling, JavaScript object denition, HTML element positioning, and more

DWR

DWR (Direct Web Remoting) provides tight integration with Java DWR provides two major functions:

A dynamic JavaJavaScript proxy generation library (engine.js) Utility library of miscellaneous JavaScript functionality (util.js)

Using DWR

Step 1: Add the DWR servlet to your project Step 2: Create a DWR conguration le Step 3: Add DWR JavaScript to your HTML

The DWR Servlet

Step 1: Congure the DWR servlet


<servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class> uk.ltd.getahead.dwr.DWRServlet </servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping>

The DWR Servlet

The DWR servlet provides some fairly neat interactive capabilities

http://[host]:[context]/dwr/ Consider turning off debugging before deploying to production

Conguring DWR

Step 2: Congure DWR

DWR does not allow arbitrary execution of any Java code unless you explicitly expose the Java code Exposure of Java classes occurs in a DWR-specic conguration le: dwr.xml

Simple dwr.xml
Specify how to create the object (i.e., Spring vs new)
* classes not instantiated when a method is static

Specify an arbitrary name for the JavaScript proxy

<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr> <allow> <create creator="new" javascript="Validator"> <param name="class" value="org.galbraiths.Validator"/> </create> </allow> </dwr>

Specify the class to expose

JavaScript

Step 3: Add DWR JavaScript

DWR servlet acts as a mini-server for delivering JavaScript to the browser Dynamically generates JavaScript proxy objects at run-time You must explicitly reference a JavaScript le for each proxy you wish to use

JavaScript Example
Core DWR JavaScript: required for proxy stuff Proxy JavaScript: required to access an instance of the Java Validator type
<script type="text/javascript" src="/dwr/engine.js"></script> <script type="text/javascript" src="/dwr/Validator.js"></script> <script type=text/javascript> Validator.echoMethod(Hello, world!, callback); function callback(data) { alert(data); } </script>

DWR creates JavaScript methods that proxy the Java methods


public String echoMethod(String arg) { return arg; }

DWR Conguration

You can restrict the set of methods exposed on an object

Use either an include or exclude model, but not both Can integrate with JAAS to require a role for method invocation

You can set the scope of the beans DWR instantiates

DWR Conguration

By default, DWR blocks remoting of arbitrary JavaBeans

But, you can enable it easily enough (see next slide)

Remember, JavaScript does not support method overloading

Most recent denition wins (is the order guaranteed? not likely)

Example
<dwr> <allow> <create creator="new" javascript="Ledger" scope="request"> <param name="class" value="org.galbraiths.Ledger"/> <exclude method="revealSensitiveFinancialInfo"/> <auth method="cheatEmployeesOutOfMoney" role="boss"/> </create> <create creator="new" javascript="Validator"> <param name="class" value="org.galbraiths.Validator"/> <include method="validateCustomerId"/> <include method="validateTicketNumber"/> </create> <convert converter="bean" match="org.galbraiths.SomeBean"/> </allow> </dwr>

Extensibility

DWR allows you to dene new ways to create beans and custom converters for JavaBeans

"creators" and "converters" must be registered in an <init> element in the conguration le:
<init> <creator id="..." class="..."/> <converter id="..." class="..."/> </init>

Additional Features

DWR makes it easy to display a "Loading..." indicator

Exposes a pre- and post- hook after some remote operation takes place:

DWREngine.setPreHook(function) DWREngine.setPostHook(function)

Additional Features

Worried about latency? DWR allows you to batch opereations:

DWREngine.beginBatch() DWREngine.endBatch()

Race conditions caused by asynchronicity got you down?

DWREngine.setOrdered(true) forces serial FIFO execution of DWR requests

Script.aculo.us

Requires Prototype Reduces many effects to one line of JavaScript:
<div onclick="new Effect.Fade(this)"> ... </div>

The Effects

Each effect takes either a DOM node or the element id (or multiple element ids) Effect.*:

Appear, Fade, Puff, BlindDown, BlindUp, SwitchOff, SlideDown, SlideUp, DropOut, Shake, Pulsate, Squish, Fold, Grow, Shrink, Highlight

Debugging Tips

Use the DOM Inspector to observe the current state of your page

Use MODI for easier live inspection and DOM manipulation

Use the JavaScript console to check for errors Use MochiKit logging and interpreter Use Venkman or Microsoft Script Debugger to troubleshoot behaviorial problems Or, just use Firebug

Futures?
SVG Canvas JIT Off-line Flash

S-ar putea să vă placă și