Upgrade to Pro — share decks privately, control downloads, hide ads and more …

progressive enhancement for JS apps

progressive enhancement for JS apps

When progressive enhancement–offering a basic version of a feature that all clients can use as a default–was introduced as a concept, JavaScript applications seemed as relevant as flying cars. As JS became more powerful, it seemed we'd reach a point where we could forget about PE entirely. For the things we originally used it for, we now have rock-solid libraries and polyfills to provide abstractions that make PE easy. But as JS has advanced, we've started writing things that can't be polyfilled. We know now how to progressively enhance widgets and user interactions. We'll talk about how we progressively enhance entire applications, and why it's potentially more important than ever that we do so.

Garann Means

May 09, 2014
Tweet

More Decks by Garann Means

Other Decks in Technology

Transcript

  1. a little case study tons and tons of JS real-time

    collaborative offline capabilities* fallback: a textarea
  2. 2003-2008 “let’s use JS for everything!” “what, people have JS

    turned off?” “what, browser support is inconsistent?”
  3. 2003-2008 “let’s use JS for everything!” “what, people have JS

    turned off?” “what, browser support is inconsistent?” “who cares, our customers are cutting edge”
  4. 2003-2008 “let’s use JS for everything!” “what, people have JS

    turned off?” “what, browser support is inconsistent?” “who cares, our customers are cutting edge” from yesterday: “if you’re seeing a broken experience, your environment is broken”
  5. 2003-2008 “let’s use JS for everything!” “what, people have JS

    turned off?” “what, browser support is inconsistent?” “who cares, our customers are cutting edge” from yesterday: “if you’re seeing a broken experience, your environment is broken” “oh weird our business failed”
  6. why’d we switch? degradation is harder to plan accurately degradation

    makes things even slower for less powerful clients hope for the best, plan for the worst
  7. JS apps “oh, but this isn’t for people who don’t

    have JavaScript” “..or people returning to the site”
  8. JS apps “oh, but this isn’t for people who don’t

    have JavaScript” “..or people returning to the site” “..or people going through a tunnel on a train”
  9. have we learned nothing? obviously we want the best experience

    possible this is the internet; “possible” changes brittle expectations of our users means a worse experience for everyone
  10. a method build servers as if every client is text-only

    build clients as if the internet will disappear tomorrow expect people not to use the app the way you expected
  11. some simple principles state is shared between client and server

    the client takes responsibility for state offline and attempts to sync when it comes online actions, by default, occur on both client and server
  12. “computer, enhance!” is JS available? great, run the client-side app

    are we online? great, send updates to the server
  13. “computer, enhance!” is JS available? great, run the client-side app

    are we online? great, send updates to the server client and server aren’t in sync? no problem, put them in sync
  14. state runs the app interface changes fetching data app logic

    updates the state state changes trigger everything else
  15. same on the server app.get( “/register/:step?”, function( req, res )

    { var step = req.params.step || registration_step; res.render( “reg_step_” + step, registration_data ); });
  16. glad you asked! updates about state are separate from updates

    as a result of state data updates are chunked state updates are instant (if possible)
  17. everything handled function set_registration_step( step ) { my_app.state.registration_step = step;

    update_state( “registration_step_” + step ); var data = get_data( step - 1 ); save_data( ( step - 1 ), data ); $( “form-step-” + step ).show(); }
  18. and stored function save_data( step, data ) { db.put( data,

    “registration_” + step, function( err, response ) { if ( err ) { show_error( “Data not saved!” ); } }); }
  19. note: plan your storage small apps may be able to

    be stored entirely only the current workflow in large apps may be able to be stored the more changes happen offline, the less room for potentially used data
  20. how does the client know it ’s offline? poll for

    server updates catch a socket error sending data via normal XHR wait for an error saving
  21. hope for the best, plan for the worst function update_state(

    state ) { state_cache.push( state ) var req = $.ajax({ type: “POST”, url: “/update_state”, data: state_cache }).done( function() { state_cache = []; }).fail( function( xhr, err ) { if ( err == “timeout” ) start_heartbeat(); }); }
  22. how do know you’re back? try it navigator.onLine probably some

    sort of heartbeat no matter your strategy
  23. and then: send client’s current state follow a defined path

    from server’s current state to client’s or send specific steps from the client sync server data with client
  24. so let ’s talk actions <input type=”submit” value=”Continue ‛” />

    <!-- NO NO NO NO NO NO NO NO NO NO NO <div id=”save-step-1”>Continue ‛</div> -->
  25. actions in the interface never trigger actions directly actions are

    triggered by state changes state changes update client and server then the action itself occurs
  26. saving (for example) fetches user-entered data from the interface stores

    it in an application variable adds it to the local data store notifies the server that a save occurred syncs data
  27. ..then the server default: fetches user-entered data from the client

    enhanced: syncs with client DB stores it in an application variable adds it to the backend data store notifies any other connected clients that there are changes
  28. other connected clients & reloads fetches user-entered data from the

    server stores it in an application variable adds it to its local data store updates its interface
  29. if JS disappears we use HTML behaviors (links, buttons) to

    skip right to the server step concurrent users receive immediately-expiring data
  30. tada: it ’s progressive! our server has a version of

    the app and can render its interface client side can continue without the server, in case we go offline real-time communication and multiple concurrent users follow the same pattern
  31. our app is now usable by multiple clients in multiple

    locations and easier to continue extending by layering functionality, as with progressive enhancement