Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Writing Asynchronous Javascript 101

A brief introduction to writing asynchronous javascript. A presentation from work.

  • Login to see the comments

Writing Asynchronous Javascript 101

  1. 1. WritingAsynchronousJavascript 101 Matt 2011.10.14
  2. 2. Javascript 101
  3. 3. How does this work?function loadPage () { $(‘#spinner’).show(); setupPage(); $(‘#spinner’).hide();}
  4. 4. • A browser window has one thread that renders the DOM, dispatches events and executes Javascript.• This thread executes one code unit at a time.• Other code units are queued until the current code unit is finished executing.
  5. 5. It doesn’t.function loadPage () { // The DOM manipulation tasks // are not executed until this // task’s stack clears. The spinner // isn’t shown until setUp is // completed. $(‘#spinner’).show(); setupPage(); $(‘#spinner’).hide();}
  6. 6. Use an asynchronous task.function loadPage () { $(‘#spinner’).show(); // Queue a task to execute // when this stack clears. setTimeout(function () { setupPage(); $(‘#spinner’).hide(); }, 0);}
  7. 7. Javascript needs Async• Javascript is single threaded (mostly)• Long running tasks kill user experience• Long running tasks will timeout (especially on mobile browsers)• Thus, most I/O APIs are asynchronous • Ajax, WebSQL, IndexedDB, WebWorkers
  8. 8. Aside: Types of Javascript Tasks• Events• Timed scripts - setTimeout, setInterval• Callbacks - Ajax, WebSQL, WebWorkers, etc.• Script Tags• Javascript URLs• Others?
  9. 9. So how you do write asynchronous Javascript?
  10. 10. Callbacks!asyncStorage.get(key, function (val) { doSomething(val);}); • Javascript has no syntactic way of dealing with asynchronous code (unlike Erlang and co.) • We’re stuck with callbacks. • Callback programming can get complex.
  11. 11. Callback programming is hard.
  12. 12. Reason #1:Error Handling
  13. 13. How does this work?try { asyncStorage.get(key, function (val) { throw new Error(“argh”); });} catch (error) { alert(‘error!’);}
  14. 14. It doesn’t.• Tasks don’t share stacks.• Thus, errors in asynchronous callbacks won’t bubble up to callers.• Errors must be manually passed back to callers via callback functions.• There are two styles of doing this.
  15. 15. Different Styles// Have separate “onSuccess” and “onError”// callbacks. Used by WebSQLDatabase, jQuery, etc.var onSuccess = function (value) { doSomething(value); };var onFailure = function (error) { alert(‘aw shucks’); };asyncStorage.get(key, onSuccess, onFailure);// Use a single callback. If errors occur, they are// passed as the first argument to the callback. It// is up to the caller to check if the first argument// is non-null. This is a node.js convention and is// reminiscent of error checking in C.asyncStorage.get(key, function (error, value) { if (error) { alert(‘aw shucks error’); return; // Don’t forget this! } doSomething(value);});
  16. 16. In summary ...• Passing errors around via callbacks is a pain.• It requires much more discipline, more testing and some understanding of how the browser works.• Consistency is important. Choose one error passing style for your application.
  17. 17. Reason #2:Control Flow
  18. 18. Reason #2:Control Flow
  19. 19. Synchronous Flow is Easy/** * Show a list of songs for the artist with * the given name. */function showSongs (artistName) { var artist = artists.getByName(artistName); var albums = albums.getByArtist(artist); var songs = songs.getByAlbum(albums); songView.render(songs);}
  20. 20. Async flow is Spaghetti/** * Show a list of songs for the artist with * the given name and execute the callback when * complete. */function showSongs (artistName, callback) { // And we’re not even handling errors! artists.getByName(name, function (artist) { albums.getByArtist(artist, function (albums) { songs.getByAlbum(albums, function (songs) { songView.render(songs); return callback(); }); }); });}
  21. 21. Control Flow Code Helps• Avoid a filthy rat’s nest of callbacks.• Keep your tasks disjoint from your control flow.• Control flow is readable in one place.
  22. 22. Control Flow Libraries• async.js - • async functional utilites + control flow• do.js - • control flow via continuables• jquery.deferred.js - • promises• language extentions options, others
  23. 23. Let’s check out async.js• One of many means of doing control flow.• asynchronous functional utilities • e.g. each, map• async control flow • e.g. series, parallel, waterfall
  24. 24. Examplefunction showSongs (artistName, callback) { var renderTask = function (songs, renderCallback) { try { songView.render(songs); return renderCallback(null); // No errors! } catch (error) { return renderCallback(error); } }; // The control flow is encapsulated in one place // in clear, concise, readable manner. var tasks = [ async.apply(artists.getByName, artistName), async.apply(albums.getByArtist), async.apply(songs.getByAlbum), async.apply(renderTask) ]; async.waterfall(tasks, callback);}
  25. 25. In summary• Callbacks don’t scale.• You need to build scaffolding to manage the complexity.• Separate your control flow from your tasks.
  26. 26. Reason #3:Debugging
  27. 27. Ease the pain (a little)• Add module or class names to console log messages to easily trace the flow.• Breakpoints everywhere!• This still sucks.
  28. 28. Conclusion• Writing asynchronous Javascript is hard.• Complexity can spiral out of control.• Plan for it.• Beware.• Good luck.
  29. 29. Fin.Questions? Comments?
  30. 30. Further reading• synchronization-in-javascript/•• work/multipage/webappapis.html#event-loops