This document discusses challenges with maintaining application state and browser history when using asynchronous JavaScript (Ajax). It presents solutions for handling out-of-order responses and preserving the back button functionality. The Yahoo User Interface (YUI) library is recommended for its browser history tool, which uses anchors to track browser history without reloading pages. Code examples are provided for initializing and using the YUI browser history manager.
1. State & Ajax
Oil and Water
paul reinheimer
php|architect
Application State Browser State Browbeating
Maintaining application The back button isn’t
state within an yours, stop breaking it. You’ve been bad.
asynchronous Also Bookmarks! Sorry :(
application (Uses YUI)
2. >whoami
๏ Hi!
๏ Paul Reinheimer
๏ Full time instructor for php|architect
๏ Author Professional Web APIs with PHP
๏ P3 Podcast
๏ Acquisition editor for C7Y Articles
๏ Doc team member php.net
๏ Some other stuff
3. Talk Synopsis
๏ Ajax is really nifty
๏ It has two big problems: Application state in an
asynchronous world and browser history.
๏ Application State
๏ When you make sequential requests, they might come
back in a different order
๏ Browser State
๏ We broke the back button, it wasn’t ours. We have to give
the ball back.
4. Why you should care
๏ Customers abandon shopping carts and experiences all
the time, both traditionally (brick & mortar).
๏ They abandon these experiences for external reasons
(from a technology prospective) like cost, time,
availability, suitability.
๏ They also abandon these experiences when sites don’t
work, break, mis-behave, or become too difficult to use.
5. Caring is Counting the cash
๏ Ensure your entire development team is on board for
providing consistent Ajax experiences that meet user
expectations.
๏ Build from the start. Don’t add in a week before go-live.
Untested = Fail.
๏ Websites that continuously provide excellent user
experiences are more likely to be visited, re-visited,
shared, and praised.
๏ Websites that have the above are more likely to achieve
goals.
6. Application State
๏ If you ask someone what Ajax stands for, they might
answer it doesn’t stand for anything, or they might say
“Asynchronous JavaScript And XML”
๏ Asynchronous means that you’re welcome to send
requests one after another, but they’re not guaranteed to
return in that order.
๏ If your application isn’t ready to handle those responses
returning in jumbled order, it isn’t really ready to go live.
7. Asynchronous
๏ Unlike PHP JavaScript can be approached as an event
based language: users can initiate multiple events in
rapid succession
๏ Depending on routing, and script length they can take
effect on the server, or return in differing order.
๏ During testing you may initiate actions A -> B -> C, your
users however may have other orders in mind.
8. Does it matter
๏ Yes!
๏ Selecting a country in a drop dow list
๏ Cambodia
๏ Cameroon
๏ Canada
๏ Failing a login then correcting
๏ Muscle Memory
๏ Logging in, then activating another control that behaves
differently depending on your login state
๏ Users are impatient
9. It gets worse
๏ Under load everything gets slower, but different scripts
get slower at different rates
http://example.preinheimer.com/zendcon/latency.html
๏ Scripts that initially took similar amounts of time can take
radically different amounts of time once the server
experiences load.
10. Not always a problem
๏ This isn’t a problem you need to solve every single time,
it depends on your application and the specific action.
Actions like queuing like canceling can simply slow your
application down.
11. Solutions?
๏ Several Possible Solutions:
๏ Queue Queries against the server
๏ http://example.preinheimer.com/ajaxCourse/blockingLatency.php
๏ Cancel old requests
๏ If the information is now irrelevant, toss it
๏ Maintain state
๏ Know what your application is doing, and manage it.
12. Choosing a Solution
๏ Failed Login Attempts
๏ Cancel old requests
๏ Selecting a country
๏ Queueing or Canceling
๏ Logging in, then activating another control
๏ Block on other actions
13. Multiple Solutions
๏ Some pages may
involve multiple
solutions, know
how your page
interacts with
itself.
14. The server side catch
๏ Canceling requests can have repercussions on the server
side script.
๏ Different languages handle it differently, We will concentrate
on... PHP (selected randomly)
๏ What happens to a running PHP script when a user hits
the stop button or a request is otherwise cancelled?
15. Ignore User Abort
๏ When a request is cancelled PHP really has no idea,
there isn’t a communication mechanism in place for PHP
to be informed, it just trudges on... Until it attempts to
actually transmit data to the client, at which point it is
terminated.
๏ Ignore User Abort (php.ini, and function) allows you to
instruct PHP to continue execution while it lacks an
output resource.
16. Application State
๏ Consider it
๏ Users are random
๏ Users are impatient, they click often and hard
๏ Touch screens on airplanes, worst idea ever
๏ We can give them what they want, we just need to
ponder the real problems.
17. Browser State
๏ We broke the back button
๏ It wasn’t ours in the first place
๏ It really matters
๏ We Failed.
18. The Back Button
๏ Pre Ajax
๏ The Back button is a simple control that provides a
perfect user safety net, it doesn’t matter what you do,
what you click on, you can take it back with one click.
19. The Back Button
Web 2.0 Broke the Web
The back button is now either a
simple undo of a previous
action to a catastrophic Stop breaking things!
reversal of one to many
different actions. That button
may undo that selection you
just made, or it may take you
back to the last page you were
at before you logged in.
20. The Back Button
๏ The Real Problem
๏ The Back Button is basically a stack, replaying URIs. Every
time the URI changes the stack is pushed, when you hit
back the stack is popped. When you change the page
without changing the URI there’s no stack action.
21. The Web
๏ Okay, the web was broken already, browsers take a hand in that.
Sure there’s this thing called HTML, and it has a spec, but no one
understands what it actually means, if they do understand it, they
“understand” it different than everyone else:
๏ Deprecated. This attribute sets the size of the font.
Possible values:
๏ An integer between 1 and 7. This sets the font to some fixed
size, whose rendering depends on the user agent. Not all user
agents may render all seven sizes.
๏ A relative increase in font size. The value quot;+1quot; means one
size larger. The value quot;-3quot; means three sizes smaller. All
sizes belong to the scale of 1 to 7.
23. The Back Button
๏ Can This Even be solved?
๏ Yes
๏ The trick is those fancy mid page anchors that people used
back when GeoCities was cool. index.html#heading
๏ The page doesn’t reload, but the browser counts it as a
stack action.
24. Browsers
Browser Suck, Internet
Explorer in particular, but they
all suck at least a little.
You could spend the next
several years of your life, lose
It’s not all your fault
some hair, and cry a little (I
cried a lot) to try and handle
differences, or you could use a
library.
25. YUI
๏ ... Or you could use Yahoo User Interface (YUI)
๏ Why Choose YUI
๏ Documentation!
๏ Browser History tool works really well
๏ Great videos
๏ Active Development
๏ Documentation
26. YUI - Tips
๏ Cheat Sheets
๏ Strip down examples to learn the ropes
๏ Save debugging files (multiple versions)
๏ Firebug
27. Browser History Object
๏ It’s kind of complicated, but it’s not their fault (browsers!)
๏ An iFrame is used to help internet explorer along, point it
at a resource on the same server you’re going to use
anyways.
๏ The resource needs to be initialized with a string, rather
than an integer.
28. YUI Library: Browser History Manager 2008-2-19 v2.5
Getting Started with Browser History Manager Storing New History Entries: The navigate Method YAHOO.util.History Methods:
getBookmarkedState(str module)
1. Required Markup Any registered module can create a new history entry at any time. Doing so returns str bookmarked state
creates a new “stop” to which the user can navigate to via the back/forward getCurrentState(str module) returns str
The Browser History Manager requires the following in-page markup: buttons and that can be bookmarked in the browser. You can create new history current state
entries in your script using the navigate method. getQueryStringParameter(str param
<iframe id=quot;yui-history-iframequot; src=quot;assetquot;></iframe> name[, str query string]) returns str
<input id=quot;yui-history-fieldquot; type=quot;hiddenquot;> YAHOO.util.History.navigate(str module, str new state); param value
initialize(str stateFieldId, str
1. The asset loaded in the IFrame must be in the same domain as the Arguments: histFrameId)
page (use a relative path for the src attribute to make sure of that) navigate(str module, str state) returns
2. The asset loaded in the IFrame does not have to be an HTML 1. module: Module identifier you used when you registered the module. Boolean success
document. It can be an image for example (if you use an image that 2. new state: String representing the new state of the module. multiNavigate(arr states) returns
Boolean success
you also happen to use in your page, you will avoid an unnecessary Note: The navigate method returns a Boolean indicating whether the new state was successfully stored.
Note: The multiNavigate method allows you to change the state of several modules at once, creating a single register(str module, str initial state, fn
round-trip, which is always good for performance) callback[, obj associated object, b
history entry, whereas several calls to navigate would create several history entries.
3. This markup should appear right after the opening <body tag. scope])
2. Module Registration and the register Method A Sample Interaction
Dependencies
Use the following code to register a module:
YAHOO.util.History.register(str module, str initial Browser History Manager
state, fn callback[, obj associated object, b scope]) requires the YAHOO Global
Object and the Event Utility.
Arguments:
1. module: Arbitrary, non empty string identifying the module.
2. Initial state: Initial state of the module (corresponding to its earliest
history entry). YAHOO.util.History.getBookmarkedState may
be used to find out what this initial state is if the application was
accessed via a bookmark.
3. callback: Function that will be called whenever the Browser History
Manager detects that the state of the specified module has changed.
Use this function to update the module’s UI accordingly.
4. associated object: Object to which your callback will have access;
often the callback’s parent object.
5. scope: Boolean – if true, the callback runs in the scope of the
associated object.
3. Using the onReady Method
Once you’ve registered at least one module, you should use the Browser
History Manager's onReady method. In your handler, you should
initialize your module(s) based on their current state. Use the function
YAHOO.util.History.getCurrentState to retrieve the current
state of your module(s).
YAHOO.util.History.onReady(function () {
var currentState =
YAHOO.util.History.getCurrentState(quot;modulequot;);
// Update UI of module to match current state
});
4. Initializing the Browser History Manager
Before using the Browser History Manager, you must initialize it, passing
in the id of the required HTML elements created in step 1:
YAHOO.util.History.initialize(quot;yui-history-fieldquot;,
quot;yui-history-iframequot;);
29. Example
๏ XKCD is Great
๏ So was penny arcade, but they swear a lot
๏ We can start on any page, navigate at will and the back
button retains full functionality.
๏ Code!
30. Browser State
๏ Fixing the back button returns essential control to your
end users.
๏ Happy users buy products, tell friends, return to the site,
all those exciting things.
32. Special Thanks
๏ Yahoo!
๏ Great Tools, docs that don’t suck
๏ Firebug & Dragonfly
๏ Ajax life, worth living
๏ Audience
๏ Talking to yourself gets old somewhere into the third hour.