callbacks, promises, and coroutines (oh my!): asynchronous programming patterns in javascript
DESCRIPTION
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.TRANSCRIPT
![Page 1: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/1.jpg)
Callbacks, Promises, and Coroutines (oh my!)
Asynchronous Programming Patterns in JavaScript
Domenic Denicolahttp://domenicdenicola.com
@domenicdenicola
![Page 2: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/2.jpg)
In non-web languages,
most of the code we write is synchronous.
aka blocking
![Page 3: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/3.jpg)
Console.WriteLine("What is your name?");string name = Console.ReadLine();Console.WriteLine("Hello, " + name);
![Page 4: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/4.jpg)
var fileNames = Directory.EnumerateFiles("C:\\"); foreach (var fileName in fileNames){ using (var f = File.Open(fileName, FileMode.Open)) { Console.WriteLine(fileName + " " + f.Length); }}
![Page 5: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/5.jpg)
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"));}
![Page 6: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/6.jpg)
This often causes us some pain…
… but hey, there’s always threads!
Thread.Start BackgroundWorker
ThreadPool
.AsParallel()
Dispatcher.Invoke
Control.InvokeRequired
![Page 7: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/7.jpg)
Q: What are these threads doing, most of the time?
A: waiting
![Page 8: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/8.jpg)
WTF!?
![Page 9: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/9.jpg)
In JavaScript, we do things differently.
![Page 10: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/10.jpg)
There’s only one thread in JavaScript,
so we use that thread to get stuff done.
![Page 11: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/11.jpg)
OK, let’s talk about…
• The event loop• Callbacks• Promises• Coroutines
![Page 12: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/12.jpg)
THE EVENT LOOP
![Page 13: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/13.jpg)
You’ve seen event loops before:
![Page 14: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/14.jpg)
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;}
![Page 15: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/15.jpg)
this.btnOK.Click += this.btnOK_Click; private void btnOK_Click(object sender, EventArgs e){ // ...}
![Page 16: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/16.jpg)
$("#ok-button").click(function () { // ...}); setTimeout(function () { // ...}, 100); $.get("http://example.com", function (result) { // ...});
![Page 17: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/17.jpg)
Some event loop subtleties
• Yielding• Async’s not sync• Errors• It’s not magic
![Page 18: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/18.jpg)
console.log("1"); $.get("/echo/2", function (result) { console.log(result);}); console.log("3"); // 1, 3, 2
YieldingEvent Loop Subtleties
![Page 19: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/19.jpg)
var hi = null; $.get("/echo/hi", function (result) { hi = result;}); console.log(hi); // null
Async’s not syncEvent Loop Subtleties
![Page 20: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/20.jpg)
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...");
ErrorsEvent Loop Subtleties
![Page 21: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/21.jpg)
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 ... 2
It’s not magicEvent Loop Subtleties
http://teddziuba.com/2011/10/node-js-is-cancer.html
![Page 22: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/22.jpg)
The event loop is tricky… but powerful.
![Page 23: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/23.jpg)
CALLBACKS
![Page 24: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/24.jpg)
What we’ve seen so far has been doing asynchronicity through
callbacks.
![Page 25: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/25.jpg)
Callbacks are OK for simple operations, but force us into
continuation passing style.
![Page 26: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/26.jpg)
Recurring StackOverflow question:
function getY() { var y; $.get("/gety", function (jsonData) { y = jsonData.y; }); return y;} var x = 5;var y = getY(); console.log(x + y);
Why doesn’t it work???
![Page 27: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/27.jpg)
After getting our data, we have to do
everything else in a continuation:
![Page 28: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/28.jpg)
function getY(continueWith) {
$.get("/gety", function (jsonData) {
continueWith(jsonData.y);
});
}
var x = 5;
getY(function (y) {
console.log(x + y);
});
![Page 29: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/29.jpg)
CPS Headaches
• Doing things in sequence is hard• Doing things in parallel is harder• Errors get lost easily
![Page 30: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/30.jpg)
Doing things in sequence is hard$("#button").click(function () { promptUserForTwitterHandle(function (handle) { twitter.getTweetsFor(handle, function (tweets) { ui.show(tweets); }); });});
CPS Headaches
![Page 31: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/31.jpg)
Doing things in parallel is hardervar 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();});
CPS Headaches
![Page 32: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/32.jpg)
Doing things in parallel is hardervar finishedSoFar = 0; function somethingFinished() { if (++finishedSoFar === 3) { ui.show(tweets, answers, checkins); }}
CPS Headaches
![Page 33: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/33.jpg)
Errors get lost easilyfunction 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(); }); }); });}
CPS Headaches
![Page 34: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/34.jpg)
You could write your own library to make this nicer…
![Page 35: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/35.jpg)
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); });}
![Page 36: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/36.jpg)
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]);});
![Page 37: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/37.jpg)
And in fact many people have:
https://github.com/joyent/node/wiki/modules#wiki-async-flow
![Page 38: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/38.jpg)
The best of these (IMO) are based on
an abstraction called “promises”
![Page 39: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/39.jpg)
PROMISES
![Page 40: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/40.jpg)
Un-inverts the chain of responsibility:
instead of calling a passed callback, return a promise.
![Page 41: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/41.jpg)
addWithCallback(a, b, function (result) { assert.equal(result, a + b);}); var promise = addWithPromise(a, b); promise.then(function (result) { assert.equal(result, a + b);});
![Page 42: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/42.jpg)
Why promises are awesome
• Cleaner method signatures• Uniform return/error semantics• Easy composition• Easy sequential/parallel join• Always async• Exception-style error bubbling
![Page 43: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/43.jpg)
Cleaner method signaturesUniform return/error semantics
$.get( url, [data], [success(data, status, xhr)], [dataType])
Promises are Awesome
![Page 44: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/44.jpg)
Cleaner method signaturesUniform return/error semantics
$.ajax(url, settings)
settings.success(data, status, xhr)settings.error(xhr, status, errorThrown)settings.complete(xhr, status)
Promises are Awesome
![Page 45: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/45.jpg)
Cleaner method signaturesUniform return/error semantics
fs.open( path, flags, [mode], [callback(error, file)])
Promises are Awesome
![Page 46: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/46.jpg)
Cleaner method signaturesUniform return/error semantics
fs.write( file, buffer, offset, length, position, [callback(error, written, buffer)])
Promises are Awesome
![Page 47: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/47.jpg)
Cleaner method signaturesUniform 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("Couldn't get", error); });
Promises are Awesome
![Page 48: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/48.jpg)
Easy composition
function getUser(userName, onSuccess, onError) { $.ajax("/user?" + userName, { success: onSuccess, error: onError });}
Promises are Awesome
![Page 49: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/49.jpg)
Easy composition
function getUser(userName) { return getAsPromise("/user?" + userName);}
Promises are Awesome
![Page 50: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/50.jpg)
Easy composition
function getFirstName(userName, onSuccess, onError) { $.ajax("/user?" + userName, { success: function successProxy(data) { onSuccess(data.firstName); }, error: onError });}
Promises are Awesome
![Page 51: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/51.jpg)
Easy composition
function getFirstName(userName) { return getAsPromise("/user?" + userName) .get("firstName");}
Promises are Awesome
![Page 52: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/52.jpg)
Easy sequential join
$("#button").click(function () { promptUserForTwitterHandle(function (handle) { twitter.getTweetsFor(handle, function (tweets) { ui.show(tweets); }); });});
Promises are Awesome
![Page 53: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/53.jpg)
Easy sequential join
$("#button").clickPromise() .then(promptUserForTwitterHandle) .then(twitter.getTweetsFor) .then(ui.show);
Promises are Awesome
![Page 54: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/54.jpg)
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();});
Promises are Awesome
![Page 55: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/55.jpg)
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]);});
Promises are Awesome
![Page 56: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/56.jpg)
Easy parallel join
Q.all([ twitter.getTweetsFor("domenicdenicola"), stackOverflow.getAnswersFor("Domenic"), fourSquare.getCheckinsBy("Domenic")]).spread(function (tweets, answers, checkins) { console.log(tweets, answers, checkins);});
Promises are Awesome
![Page 57: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/57.jpg)
Always async
function getUser(userName, onSuccess, onError) { if (cache.has(userName)) { onSuccess(cache.get(userName)); } else { $.ajax("/user?" + userName, { success: onSuccess, error: onError }); }}
Promises are Awesome
![Page 58: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/58.jpg)
Always async
console.log("1"); getUser("ddenicola", function (user) { console.log(user.firstName);}); console.log("2");
// 1, 2, Domenic
Promises are Awesome
![Page 59: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/59.jpg)
Always async
console.log("1"); getUser("ddenicola", function (user) { console.log(user.firstName);}); console.log("2");
// 1, Domenic, 2
Promises are Awesome
![Page 60: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/60.jpg)
Always async
function getUser(userName) { if (cache.has(userName)) { return Q.ref(cache.get(userName)); } else { return getWithPromise("/user?" + userName); }}
Promises are Awesome
![Page 61: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/61.jpg)
Always async
console.log("1"); getUser("ddenicola").then(function (user) { console.log(user.firstName);}); console.log("2");
// 1, 2, Domenic (every time)
Promises are Awesome
![Page 62: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/62.jpg)
Exception-style error bubbling
getUser("Domenic", function (user) { getBestFriend(user, function (friend) { ui.showBestFriend(friend); });});
Promises are Awesome
![Page 63: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/63.jpg)
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); } }); }});
Promises are Awesome
![Page 64: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/64.jpg)
Exception-style error bubbling
getUser("Domenic") .then(getBestFriend, ui.error) .then(ui.showBestFriend, ui.error);
Promises are Awesome
![Page 65: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/65.jpg)
Exception-style error bubbling
getUser("Domenic") .then(getBestFriend) .then(ui.showBestFriend, ui.error);
Promises are Awesome
![Page 66: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/66.jpg)
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(); } );
Promises are Awesome
![Page 67: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/67.jpg)
Exception-style error bubbling
ui.startSpinner();getUser("Domenic") .then(getBestFriend) .then(ui.showBestFriend, ui.error) .fin(ui.stopSpinner);
Promises are Awesome
![Page 68: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/68.jpg)
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; });}
Promises are Awesome
![Page 69: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/69.jpg)
Sounds great. How do I get in on this action?
![Page 70: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/70.jpg)
Use Q
• By Kris Kowal, @kriskowal• https://github.com/kriskowal/q• Can consume promises from jQuery etc.• Implements various CommonJS standards
![Page 71: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/71.jpg)
If you’re already using jQuery’s promises, switch to Q:
https://github.com/kriskowal/q/wiki/jQuery
![Page 72: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/72.jpg)
![Page 73: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/73.jpg)
Fulfilling promises
// We have:setTimeout(doSomething, 1000); // We want:delay(1000).then(doSomething);
Creating promises with Q
![Page 74: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/74.jpg)
Fulfilling promises
function delay(ms) { var deferred = Q.defer(); setTimeout(deferred.resolve, ms); return deferred.promise;} delay(1000).then(doSomething);
Creating promises with Q
![Page 75: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/75.jpg)
Breaking promisesfunction 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); } } });}
Creating promises with Q
![Page 76: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/76.jpg)
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;}
Creating promises with Q
![Page 77: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/77.jpg)
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);}
Creating promises with Q
![Page 78: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/78.jpg)
Promises are cool.
![Page 79: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/79.jpg)
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.
![Page 80: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/80.jpg)
But… we still have to write in CPS.
![Page 81: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/81.jpg)
COROUTINES
![Page 82: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/82.jpg)
“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
![Page 83: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/83.jpg)
WTF!?
![Page 84: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/84.jpg)
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);});
![Page 85: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/85.jpg)
Nicer:
var [x, y, z] = await Q.all([getX(), getY(), getZ()]); console.log(x + y + z);
![Page 86: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/86.jpg)
Nice:
$("#button").clickPromise() .then(promptUserForTwitterHandle) .then(twitter.getTweetsFor) .then(ui.show);
![Page 87: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/87.jpg)
Nicer:
await $("#button").clickPromise();
var handle = await promptUserForTwitterHandle();var tweets = await twitter.getTweetsFor(handle);
ui.show(tweets);
![Page 88: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/88.jpg)
Q: Can’t the compiler do this for me?
A: yes… if you are willing to introduce a compiler.
![Page 89: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/89.jpg)
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
![Page 90: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/90.jpg)
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.
![Page 91: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/91.jpg)
The next version of JavaScript (“ECMAScript Harmony”) has a limited form
of coroutines that can be twisted to do something like what we want.
![Page 92: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/92.jpg)
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
![Page 93: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/93.jpg)
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
![Page 94: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/94.jpg)
ECMAScript Harmony generators
// Can only use yield as we want to within// Q.async'ed 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
![Page 95: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/95.jpg)
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
![Page 96: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/96.jpg)
ECMAScript Harmony generators
Q.async(function* () { var el = document.getElementById("my-element"); yield animateAsync(el); console.log("it's done animating");})();
https://groups.google.com/d/topic/q-continuum/7PWKbgeFA48/discussion
![Page 97: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/97.jpg)
So coroutines are a bit of a mess, but we’ll see
how things shape up.
![Page 98: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/98.jpg)
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
![Page 99: Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript](https://reader034.vdocuments.mx/reader034/viewer/2022051311/540e07048d7f72747e8b4c49/html5/thumbnails/99.jpg)
Thanks for listening!