Callbacks, Promises, and Coroutines                  (oh my!)     Asynchronous Programming        Patterns in JavaScript  ...
In non-web languages,most of the code we write is synchronous.                aka blocking
Console.WriteLine("What is your name?");string name = Console.ReadLine();Console.WriteLine("Hello, " + name);
var fileNames = Directory.EnumerateFiles("C:");foreach (var fileName in fileNames){  using (var f = File.Open(fileName, Fi...
using (var client = new WebClient()){  string html =client.DownloadString("http://news.ycombinator.com");    Console.Write...
Thread.Start                               BackgroundWorker               Control.InvokeRequired        This often causes ...
Q: What are these threads doing, most of the time?A: waiting
WTF!?
In JavaScript, we do things differently.
There’s only one thread in JavaScript,so we use that thread to get stuff done.
OK, let’s talk about…•   The event loop•   Callbacks•   Promises•   Coroutines
THE EVENT LOOP
You’ve seen event loops before:
int WINAPI WinMain(HINSTANCE hInstance,                   HINSTANCE hPrevInstance,                   LPSTR lpCmdLine,     ...
this.btnOK.Click += this.btnOK_Click;private void btnOK_Click(object sender,                         EventArgs e){  // ...}
$("#ok-button").click(function () {    // ...});setTimeout(function () {    // ...}, 100);$.get("http://example.com", func...
Some event loop subtleties•   Yielding•   Async’s not sync•   Errors•   It’s not magic
Event Loop Subtleties   Yielding   console.log("1");   $.get("/echo/2", function (result) {     console.log(result);   });...
Event Loop Subtleties   Async’s not sync   var hi = null;   $.get("/echo/hi", function (result) {     hi = result;   });  ...
Event Loop Subtleties   Errors   console.log("About to get the website...");   $.ajax("http://sometimesdown.example.com", ...
Event Loop Subtleties   It’s not magic   function fib(n) {       return n < 2 ? 1 : fib(n-2) + fib(n-1);   }   console.log...
The event loop is tricky… but powerful.
CALLBACKS
What we’ve seen so far has been doing  asynchronicity through callbacks.
Callbacks are OK for simple operations, but force us into continuation passing style.
Recurring StackOverflow question:function getY() {  var y;  $.get("/gety", function (jsonData) {    y = jsonData.y;  });  ...
After getting our data, we have to do everything else in a continuation:
function getY(continueWith) {    $.get("/gety", function (jsonData) {      continueWith(jsonData.y);    });}var x = 5;getY...
CPS Headaches• Doing things in sequence is hard• Doing things in parallel is harder• Errors get lost easily
CPS Headaches  Doing things in sequence is hard  $("#button").click(function () {    promptUserForTwitterHandle(function (...
CPS Headaches  Doing things in parallel is harder  var tweets, answers, checkins;  twitter.getTweetsFor("domenicdenicola",...
CPS Headaches  Doing things in parallel is harder  var finishedSoFar = 0;  function somethingFinished() {    if (++finishe...
CPS Headaches  Errors get lost easily  function getTotalFileLengths(path, callback) {    fs.readdir(path, function (err, f...
You could write your own library to make this nicer…
function parallel(actions, callback) {  var results = [];  function finished(result) {    results.push(result);    if (res...
parallel([  function (cb) {     twitter.getTweetsFor("domenicdenicola", cb);  },  function (cb) {     stackOverflow.getAns...
And in fact many people have:https://github.com/joyent/node/wiki/modules#wiki-async-flow
The best of these (IMO) are based on  an abstraction called “promises”
PROMISES
Un-inverts the chain of responsibility:instead of calling a passed callback, return a promise.
addWithCallback(a, b, function (result) {  assert.equal(result, a + b);});var promise = addWithPromise(a, b);promise.then(...
Why promises are awesome• Cleaner method signatures• Uniform return/error semantics• Easy composition• Easy sequential/par...
Promises are Awesome  Cleaner method signatures  Uniform return/error semantics  $.get(    url,    [data],    [success(dat...
Promises are Awesome  Cleaner method signatures  Uniform return/error semantics  $.ajax(url, settings)  settings.success(d...
Promises are Awesome  Cleaner method signatures  Uniform return/error semantics  fs.open(    path,    flags,    [mode],   ...
Promises are Awesome  Cleaner method signatures  Uniform return/error semantics  fs.write(    file,    buffer,    offset, ...
Promises are Awesome  Cleaner method signatures  Uniform return/error semantics  getAsPromise(url, [data], [dataType]).the...
Promises are Awesome  Easy composition  function getUser(userName, onSuccess, onError) {    $.ajax("/user?" + userName, { ...
Promises are Awesome  Easy composition  function getUser(userName) {    return getAsPromise("/user?" + userName);  }
Promises are Awesome  Easy composition  function getFirstName(userName, onSuccess, onError) {    $.ajax("/user?" + userNam...
Promises are Awesome  Easy composition  function getFirstName(userName) {    return getAsPromise("/user?" + userName)     ...
Promises are Awesome  Easy sequential join  $("#button").click(function () {    promptUserForTwitterHandle(function (handl...
Promises are Awesome  Easy sequential join  $("#button").clickPromise()    .then(promptUserForTwitterHandle)    .then(twit...
Promises are Awesome  Easy parallel join  var tweets, answers, checkins;  twitter.getTweetsFor("domenicdenicola", function...
Promises are Awesome  Easy parallel join  Q.all([    twitter.getTweetsFor("domenicdenicola"),    stackOverflow.getAnswersF...
Promises are Awesome  Easy parallel join  Q.all([    twitter.getTweetsFor("domenicdenicola"),    stackOverflow.getAnswersF...
Promises are Awesome  Always async  function getUser(userName, onSuccess, onError) {    if (cache.has(userName)) {      on...
Promises are Awesome  Always async  console.log("1");  getUser("ddenicola", function (user) {    console.log(user.firstNam...
Promises are Awesome  Always async  console.log("1");  getUser("ddenicola", function (user) {    console.log(user.firstNam...
Promises are Awesome  Always async  function getUser(userName) {    if (cache.has(userName)) {      return Q.ref(cache.get...
Promises are Awesome  Always async  console.log("1");  getUser("ddenicola").then(function (user) {    console.log(user.fir...
Promises are Awesome  Exception-style error bubbling  getUser("Domenic", function (user) {    getBestFriend(user, function...
Promises are Awesome  Exception-style error bubbling  getUser("Domenic", function (err, user) {    if (err) {      ui.erro...
Promises are Awesome  Exception-style error bubbling  getUser("Domenic")    .then(getBestFriend, ui.error)    .then(ui.sho...
Promises are Awesome  Exception-style error bubbling  getUser("Domenic")    .then(getBestFriend)    .then(ui.showBestFrien...
Promises are Awesome  Exception-style error bubbling  ui.startSpinner();  getUser("Domenic")    .then(getBestFriend)    .t...
Promises are Awesome  Exception-style error bubbling  ui.startSpinner();  getUser("Domenic")    .then(getBestFriend)    .t...
Promises are Awesome  Exception-style error bubbling  function getBestFriendAndDontGiveUp(user) {    return getUser(user)....
Sounds great. How do I get in on this action?
Use Q•   By Kris Kowal, @kriskowal•   https://github.com/kriskowal/q•   Can consume promises from jQuery etc.•   Implement...
If you’re already using jQuery’s promises, switch to Q:    https://github.com/kriskowal/q/wiki/jQuery
Creating promises with Q   Fulfilling promises   // We have:   setTimeout(doSomething, 1000);   // We want:   delay(1000)....
Creating promises with Q   Fulfilling promises   function delay(ms) {     var deferred = Q.defer();     setTimeout(deferre...
Creating promises with Q   Breaking promises   function getWithTimeout(url, ms, onSuccess, onError) {     var isTimedOut =...
Creating promises with Q   Breaking promises   function getWithTimeout(url, ms) {     var deferred = Q.defer();       setT...
Creating promises with Q   Building abstractions   function timeout(promise, ms) {     var deferred = Q.defer();     promi...
Promises are cool.
They clean up our method signatures.They’re composable, they’re joinable,    and they’re dependably async.They unify vario...
But… we still have to write in CPS.
COROUTINES
“Coroutines are computer program            components that generalize subroutines                 to allow multiple entry...
WTF!?
Nice:var xP = getX();var yP = getY();var zP = getZ();Q.all([xP, yP, zP]).spread(function (x, y, z) {  console.log(x + y + ...
Nicer:var [x, y, z] = await Q.all([getX(), getY(), getZ()]);console.log(x + y + z);
Nice:$("#button").clickPromise()  .then(promptUserForTwitterHandle)  .then(twitter.getTweetsFor)  .then(ui.show);
Nicer:await $("#button").clickPromise();var handle = await promptUserForTwitterHandle();var tweets = await twitter.getTwee...
Q: Can’t the compiler do this for me?A: yes… if you are willing to introduce a compiler.
Several options, none perfect•   Kaffeine: http://weepy.github.com/kaffeine/•   Traceur: http://tinyurl.com/traceur-js•   ...
Q: OK well… can’t the interpreter do this for me?A: yes… if you’re willing to wait for the next version of JS.
The next version of JavaScript (“ECMAScriptHarmony”) has a limited form of coroutines that can  be twisted to do something...
ECMAScript Harmony generators function* fibonacci() {   var [prev, curr] = [0, 1];   for (;;) {     [prev, curr] = [curr, ...
ECMAScript Harmony generators var eventualAdd = Q.async(function* (pA, pB) {   var a = yield pA;   var b = yield pB;   ret...
ECMAScript Harmony generators // Can only use yield as we want to within // Q.asynced generator functions Q.async(function...
ECMAScript Harmony generators // Given promise-returning delay(ms) as before: var animateAsync = Q.async(function* (el) { ...
ECMAScript Harmony generators Q.async(function* () {   var el = document.getElementById("my-element");    yield animateAsy...
So coroutines are a bit of a mess, but   we’ll see how things shape up.
Recap•   Async is here to stay•   But you don’t have to dive into callback hell•   Use promises•   Use Q•   Maybe use coro...
Thanks for listening!
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript
Upcoming SlideShare
Loading in...5
×

Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript

88,130

Published on

This talk takes a deep dive into asynchronous programming patterns and practices, with an emphasis on the promise pattern.

We go through the basics of the event loop, highlighting the drawbacks of asynchronous programming in a naive callback style. Fortunately, we can use the magic of promises to escape from callback hell with a powerful and unified interface for async APIs. Finally, we take a quick look at the possibilities for using coroutines both in current and future (ECMAScript Harmony) JavaScript.

Published in: Technology, Business
5 Comments
256 Likes
Statistics
Notes
No Downloads
Views
Total Views
88,130
On Slideshare
0
From Embeds
0
Number of Embeds
20
Actions
Shares
0
Downloads
936
Comments
5
Likes
256
Embeds 0
No embeds

No notes for slide
  • Decouples the action from the subsequent use of the result.
  • Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript

    1. 1. Callbacks, Promises, and Coroutines (oh my!) Asynchronous Programming Patterns in JavaScript Domenic Denicola http://domenicdenicola.com @domenicdenicola
    2. 2. In non-web languages,most of the code we write is synchronous. aka blocking
    3. 3. Console.WriteLine("What is your name?");string name = Console.ReadLine();Console.WriteLine("Hello, " + name);
    4. 4. var fileNames = Directory.EnumerateFiles("C:");foreach (var fileName in fileNames){ using (var f = File.Open(fileName, FileMode.Open)) { Console.WriteLine(fileName + " " + f.Length); }}
    5. 5. using (var client = new WebClient()){ string html =client.DownloadString("http://news.ycombinator.com"); Console.WriteLine(html.Contains("Google")); Console.WriteLine(html.Contains("Microsoft")); Console.WriteLine(html.Contains("Apple"));}
    6. 6. Thread.Start BackgroundWorker Control.InvokeRequired This often causes us some pain… … but hey, there’s always threads! Dispatcher.InvokeThreadPool .AsParallel()
    7. 7. Q: What are these threads doing, most of the time?A: waiting
    8. 8. WTF!?
    9. 9. In JavaScript, we do things differently.
    10. 10. There’s only one thread in JavaScript,so we use that thread to get stuff done.
    11. 11. OK, let’s talk about…• The event loop• Callbacks• Promises• Coroutines
    12. 12. THE EVENT LOOP
    13. 13. You’ve seen event loops before:
    14. 14. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ MSG msg; while (GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}
    15. 15. this.btnOK.Click += this.btnOK_Click;private void btnOK_Click(object sender, EventArgs e){ // ...}
    16. 16. $("#ok-button").click(function () { // ...});setTimeout(function () { // ...}, 100);$.get("http://example.com", function (result) { // ...});
    17. 17. Some event loop subtleties• Yielding• Async’s not sync• Errors• It’s not magic
    18. 18. Event Loop Subtleties Yielding console.log("1"); $.get("/echo/2", function (result) { console.log(result); }); console.log("3"); // 1, 3, 2
    19. 19. Event Loop Subtleties Async’s not sync var hi = null; $.get("/echo/hi", function (result) { hi = result; }); console.log(hi); // null
    20. 20. Event Loop Subtleties Errors console.log("About to get the website..."); $.ajax("http://sometimesdown.example.com", { success: function (result) { console.log(result); }, error: function () { throw new Error("Error getting the website"); } }); console.log("Continuing about my business...");
    21. 21. Event Loop Subtleties It’s not magic function fib(n) { return n < 2 ? 1 : fib(n-2) + fib(n-1); } console.log("1"); setTimeout(function () { console.log("2"); }, 100); fib(40); // 1 ... 15 seconds later ... 2http://teddziuba.com/2011/10/node-js-is-cancer.html
    22. 22. The event loop is tricky… but powerful.
    23. 23. CALLBACKS
    24. 24. What we’ve seen so far has been doing asynchronicity through callbacks.
    25. 25. Callbacks are OK for simple operations, but force us into continuation passing style.
    26. 26. Recurring StackOverflow question:function getY() { var y; $.get("/gety", function (jsonData) { y = jsonData.y; }); return y;} Why doesn’t it work???var x = 5;var y = getY();console.log(x + y);
    27. 27. After getting our data, we have to do everything else in a continuation:
    28. 28. function getY(continueWith) { $.get("/gety", function (jsonData) { continueWith(jsonData.y); });}var x = 5;getY(function (y) { console.log(x + y);});
    29. 29. CPS Headaches• Doing things in sequence is hard• Doing things in parallel is harder• Errors get lost easily
    30. 30. CPS Headaches Doing things in sequence is hard $("#button").click(function () { promptUserForTwitterHandle(function (handle) { twitter.getTweetsFor(handle, function (tweets) { ui.show(tweets); }); }); });
    31. 31. CPS Headaches Doing things in parallel is harder var tweets, answers, checkins; twitter.getTweetsFor("domenicdenicola", function (result) { tweets = result; somethingFinished(); }); stackOverflow.getAnswersFor("Domenic", function (result) { answers = result; somethingFinished(); }); fourSquare.getCheckinsBy("Domenic", function (result) { checkins = result; somethingFinished(); });
    32. 32. CPS Headaches Doing things in parallel is harder var finishedSoFar = 0; function somethingFinished() { if (++finishedSoFar === 3) { ui.show(tweets, answers, checkins); } }
    33. 33. CPS Headaches Errors get lost easily function getTotalFileLengths(path, callback) { fs.readdir(path, function (err, fileNames) { var total = 0; var finishedSoFar = 0; function finished() { if (++finishedSoFar === fileNames.length) { callback(total); } } fileNames.forEach(function (fileName) { fs.readFile(fileName, function (err, file) { total += file.length; finished(); }); }); }); }
    34. 34. You could write your own library to make this nicer…
    35. 35. function parallel(actions, callback) { var results = []; function finished(result) { results.push(result); if (results.length === actions.length) { callback(results); } } actions.forEach(function (action) { action(finished); });}
    36. 36. parallel([ function (cb) { twitter.getTweetsFor("domenicdenicola", cb); }, function (cb) { stackOverflow.getAnswersFor("Domenic", cb); }, function (cb) { fourSquare.getCheckinsFor("Domenic", cb); }], function (results) { console.log("tweets = ", results[0]); console.log("answers = ", results[1]); console.log("checkins = ", results[2]);});
    37. 37. And in fact many people have:https://github.com/joyent/node/wiki/modules#wiki-async-flow
    38. 38. The best of these (IMO) are based on an abstraction called “promises”
    39. 39. PROMISES
    40. 40. Un-inverts the chain of responsibility:instead of calling a passed callback, return a promise.
    41. 41. addWithCallback(a, b, function (result) { assert.equal(result, a + b);});var promise = addWithPromise(a, b);promise.then(function (result) { assert.equal(result, a + b);});
    42. 42. Why promises are awesome• Cleaner method signatures• Uniform return/error semantics• Easy composition• Easy sequential/parallel join• Always async• Exception-style error bubbling
    43. 43. Promises are Awesome Cleaner method signatures Uniform return/error semantics $.get( url, [data], [success(data, status, xhr)], [dataType] )
    44. 44. Promises are Awesome Cleaner method signatures Uniform return/error semantics $.ajax(url, settings) settings.success(data, status, xhr) settings.error(xhr, status, errorThrown) settings.complete(xhr, status)
    45. 45. Promises are Awesome Cleaner method signatures Uniform return/error semantics fs.open( path, flags, [mode], [callback(error, file)] )
    46. 46. Promises are Awesome Cleaner method signatures Uniform return/error semantics fs.write( file, buffer, offset, length, position, [callback(error, written, buffer)] )
    47. 47. Promises are Awesome Cleaner method signatures Uniform return/error semantics getAsPromise(url, [data], [dataType]).then( function onFulfilled(result) { var data = result.data; var status = result.status; var xhr = result.xhr; }, function onBroken(error) { console.error("Couldnt get", error); } );
    48. 48. Promises are Awesome Easy composition function getUser(userName, onSuccess, onError) { $.ajax("/user?" + userName, { success: onSuccess, error: onError }); }
    49. 49. Promises are Awesome Easy composition function getUser(userName) { return getAsPromise("/user?" + userName); }
    50. 50. Promises are Awesome Easy composition function getFirstName(userName, onSuccess, onError) { $.ajax("/user?" + userName, { success: function successProxy(data) { onSuccess(data.firstName); }, error: onError }); }
    51. 51. Promises are Awesome Easy composition function getFirstName(userName) { return getAsPromise("/user?" + userName) .get("firstName"); }
    52. 52. Promises are Awesome Easy sequential join $("#button").click(function () { promptUserForTwitterHandle(function (handle) { twitter.getTweetsFor(handle, function (tweets) { ui.show(tweets); }); }); });
    53. 53. Promises are Awesome Easy sequential join $("#button").clickPromise() .then(promptUserForTwitterHandle) .then(twitter.getTweetsFor) .then(ui.show);
    54. 54. Promises are Awesome Easy parallel join var tweets, answers, checkins; twitter.getTweetsFor("domenicdenicola", function (result) { tweets = result; somethingFinished(); }); stackOverflow.getAnswersFor("Domenic", function (result) { answers = result; somethingFinished(); }); fourSquare.getCheckinsBy("Domenic", function (result) { checkins = result; somethingFinished(); });
    55. 55. Promises are Awesome Easy parallel join Q.all([ twitter.getTweetsFor("domenicdenicola"), stackOverflow.getAnswersFor("Domenic"), fourSquare.getCheckinsBy("Domenic") ]).then(function (results) { console.log(results[0], results[1], results[2]); });
    56. 56. Promises are Awesome Easy parallel join Q.all([ twitter.getTweetsFor("domenicdenicola"), stackOverflow.getAnswersFor("Domenic"), fourSquare.getCheckinsBy("Domenic") ]).spread(function (tweets, answers, checkins) { console.log(tweets, answers, checkins); });
    57. 57. Promises are Awesome Always async function getUser(userName, onSuccess, onError) { if (cache.has(userName)) { onSuccess(cache.get(userName)); } else { $.ajax("/user?" + userName, { success: onSuccess, error: onError }); } }
    58. 58. Promises are Awesome Always async console.log("1"); getUser("ddenicola", function (user) { console.log(user.firstName); }); console.log("2"); // 1, 2, Domenic
    59. 59. Promises are Awesome Always async console.log("1"); getUser("ddenicola", function (user) { console.log(user.firstName); }); console.log("2"); // 1, Domenic, 2
    60. 60. Promises are Awesome Always async function getUser(userName) { if (cache.has(userName)) { return Q.ref(cache.get(userName)); } else { return getWithPromise("/user?" + userName); } }
    61. 61. Promises are Awesome Always async console.log("1"); getUser("ddenicola").then(function (user) { console.log(user.firstName); }); console.log("2"); // 1, 2, Domenic (every time)
    62. 62. Promises are Awesome Exception-style error bubbling getUser("Domenic", function (user) { getBestFriend(user, function (friend) { ui.showBestFriend(friend); }); });
    63. 63. Promises are Awesome Exception-style error bubbling getUser("Domenic", function (err, user) { if (err) { ui.error(err); } else { getBestFriend(user, function (err, friend) { if (err) { ui.error(err); } else { ui.showBestFriend(friend); } }); } });
    64. 64. Promises are Awesome Exception-style error bubbling getUser("Domenic") .then(getBestFriend, ui.error) .then(ui.showBestFriend, ui.error);
    65. 65. Promises are Awesome Exception-style error bubbling getUser("Domenic") .then(getBestFriend) .then(ui.showBestFriend, ui.error);
    66. 66. Promises are Awesome Exception-style error bubbling ui.startSpinner(); getUser("Domenic") .then(getBestFriend) .then( function (friend) { ui.showBestFriend(friend); ui.stopSpinner(); }, function (error) { ui.error(error); ui.stopSpinner(); } );
    67. 67. Promises are Awesome Exception-style error bubbling ui.startSpinner(); getUser("Domenic") .then(getBestFriend) .then(ui.showBestFriend, ui.error) .fin(ui.stopSpinner);
    68. 68. Promises are Awesome Exception-style error bubbling function getBestFriendAndDontGiveUp(user) { return getUser(user).then( getBestFriend, function (error) { if (error instanceof TemporaryNetworkError) { console.log("Retrying after error", error); return getBestFriendAndDontGiveUp(user); } throw error; }); }
    69. 69. Sounds great. How do I get in on this action?
    70. 70. Use Q• By Kris Kowal, @kriskowal• https://github.com/kriskowal/q• Can consume promises from jQuery etc.• Implements various CommonJS standards
    71. 71. If you’re already using jQuery’s promises, switch to Q: https://github.com/kriskowal/q/wiki/jQuery
    72. 72. Creating promises with Q Fulfilling promises // We have: setTimeout(doSomething, 1000); // We want: delay(1000).then(doSomething);
    73. 73. Creating promises with Q Fulfilling promises function delay(ms) { var deferred = Q.defer(); setTimeout(deferred.resolve, ms); return deferred.promise; } delay(1000).then(doSomething);
    74. 74. Creating promises with Q Breaking promises function getWithTimeout(url, ms, onSuccess, onError) { var isTimedOut = false, isHttpErrored = false; setTimeout(function () { if (!isHttpErrored) { isTimedOut = true; onError(new Error("timed out")); } }, ms); $.ajax(url, { success: function (result) { if (!isTimedOut) { onSuccess(result); } }, error: function (xhr, status, error) { if (!isTimedOut) { isHttpErrored = true; onError(error); } } }); }
    75. 75. Creating promises with Q Breaking promises function getWithTimeout(url, ms) { var deferred = Q.defer(); setTimeout(function () { deferred.reject(new Error("timed out")); }, ms); $.ajax(url, { success: deferred.resolve, error: deferred.reject }); return deferred.promise; }
    76. 76. Creating promises with Q Building abstractions function timeout(promise, ms) { var deferred = Q.defer(); promise.then(deferred.resolve, deferred.reject); setTimeout(function () { deferred.reject(new Error("timed out")); }, ms); return deferred.promise; } function getWithTimeout(url, ms) { return timeout(getAsPromise(url), ms); }
    77. 77. Promises are cool.
    78. 78. They clean up our method signatures.They’re composable, they’re joinable, and they’re dependably async.They unify various callback conventions into something very much like return values and exceptions.
    79. 79. But… we still have to write in CPS.
    80. 80. COROUTINES
    81. 81. “Coroutines are computer program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations.”http://en.wikipedia.org/wiki/Coroutine
    82. 82. WTF!?
    83. 83. Nice:var xP = getX();var yP = getY();var zP = getZ();Q.all([xP, yP, zP]).spread(function (x, y, z) { console.log(x + y + z);});
    84. 84. Nicer:var [x, y, z] = await Q.all([getX(), getY(), getZ()]);console.log(x + y + z);
    85. 85. Nice:$("#button").clickPromise() .then(promptUserForTwitterHandle) .then(twitter.getTweetsFor) .then(ui.show);
    86. 86. Nicer:await $("#button").clickPromise();var handle = await promptUserForTwitterHandle();var tweets = await twitter.getTweetsFor(handle);ui.show(tweets);
    87. 87. Q: Can’t the compiler do this for me?A: yes… if you are willing to introduce a compiler.
    88. 88. Several options, none perfect• Kaffeine: http://weepy.github.com/kaffeine/• Traceur: http://tinyurl.com/traceur-js• TameJS: http://tamejs.org/• Node fork: http://tinyurl.com/node-async
    89. 89. Q: OK well… can’t the interpreter do this for me?A: yes… if you’re willing to wait for the next version of JS.
    90. 90. The next version of JavaScript (“ECMAScriptHarmony”) has a limited form of coroutines that can be twisted to do something like what we want.
    91. 91. ECMAScript Harmony generators function* fibonacci() { var [prev, curr] = [0, 1]; for (;;) { [prev, curr] = [curr, prev + curr]; yield curr; } } for (n of fibonnaci()) { console.log(n); }http://wiki.ecmascript.org/doku.php?id=harmony:generators
    92. 92. ECMAScript Harmony generators var eventualAdd = Q.async(function* (pA, pB) { var a = yield pA; var b = yield pB; return a + b; });https://github.com/kriskowal/q/tree/master/examples/async-generators
    93. 93. ECMAScript Harmony generators // Can only use yield as we want to within // Q.asynced generator functions Q.async(function* () { // Talk to the server to get one and two. var three = yield eventualAdd(getOne(), getTwo()); assert.equal(three, 3); })();https://groups.google.com/d/topic/q-continuum/7PWKbgeFA48/discussion
    94. 94. ECMAScript Harmony generators // Given promise-returning delay(ms) as before: var animateAsync = Q.async(function* (el) { for (var i = 0; i < 100; ++i) { element.style.left = i; yield delay(20); } });http://wiki.ecmascript.org/doku.php?id=strawman:async_functions
    95. 95. ECMAScript Harmony generators Q.async(function* () { var el = document.getElementById("my-element"); yield animateAsync(el); console.log("its done animating"); })();https://groups.google.com/d/topic/q-continuum/7PWKbgeFA48/discussion
    96. 96. So coroutines are a bit of a mess, but we’ll see how things shape up.
    97. 97. Recap• Async is here to stay• But you don’t have to dive into callback hell• Use promises• Use Q• Maybe use coroutines if you’re feeling brave
    98. 98. Thanks for listening!
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×