Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

409 lines (374 sloc) 12.288 kb
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Better Callbacks with Deferred Object</title>
<meta name="description" content="Introduction and examples of deferred object. ">
<meta name="author" content="Patrick Berkeley">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/beige.css" id="theme">
<!-- For syntax highlighting -->
<link rel="stylesheet" href="lib/css/zenburn.css">
<!-- If the query includes 'print-pdf', use the PDF print sheet -->
<script>
document.write( '<link rel="stylesheet" href="css/print/' + ( window.location.search.match( /print-pdf/gi ) ? 'pdf' : 'paper' ) + '.css" type="text/css" media="print">' );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section>
<h1>Deferred Object</h1>
</section>
<section>
<section>
<h1>What's the problem?</h1>
<img class='fragment' src='images/async-is-so-hard.jpg' alt='Async is so hard.' />
</section>
<section>
<p>It all starts with an innocent little ajax request:</p>
<pre class='fragment'><code>
var data;
$.get('api/data', function(resp) {
data = resp.data;
});
doSomethingFancyWithData(data);
</code></pre>
</section>
<section>
<img src='images/oh-god-why.png' alt='Oh god why.' />
<h1 class='fragment'>Where's my data?</h2>
</section>
<section>
<img src='images/picard-facepalm.jpg' alt='Picard facepalm.' />
</section>
<section>
<h1>Asychronicity</h1>
<ul>
<li class='fragment'>Sequencing is hard and leads to:
<ul>
<li class='fragment'>Continuation Passing Style (CPS).</li>
<li class='fragment'>Deep nesting.</li>
<li class='fragment'>'Callback hell'.</li>
</ul>
</li>
<li class='fragment'>Parallelizing is even harder.</li>
</ul>
</section>
<section>
<h2>Sequencing</h2>
<pre class='fragment'><code>
// Demonstrates nesting, CPS, 'callback hell'
//
$.get('api1/data', function(resp1) {
// Next that depended on the first response.
$.get('api2/data', function(resp2) {
// Next request that depended on the second response.
$.get('api3/data', function(resp3) {
// Next request that depended on the third response.
$.get(); // ... you get the idea.
});
});
});
</code></pre>
</section>
<section>
<h2>Parallelizing</h2>
<pre class='fragment'><code>
$.get('api1/data', function(resp1) { trackMe(); });
$.get('api2/data', function(resp2) { trackMe(); });
$.get('api3/data', function(resp3) { trackMe(); });
var trackedCount = 0;
function trackMe() {
++trackedCount;
if (trackedCount === 3) {
doSomethingThatNeededAllThree();
}
}
</code></pre>
</section>
<section>
<img src='images/fuuuuuuu.png' alt='FUUUUUUUUUUUUUU.' />
<h1 class='fragment'>Give me something better.</h1>
</section>
</section>
<section>
<section>
<h1>The Players</h1>
<pre class='fragment'><code>
// The deferred object itself.
var def = $.Deferred;
</code></pre>
<pre class='fragment'><code>
// And the deferred's promise object.
def.promise();
</code></pre>
</section>
<section>
<h2>$.Deferred()</h2>
<pre><code>
def;
> { always: function() {},
done: function() {},
fail: function() {},
notify: function() {},
notifyWith: function() {},
pipe: function() {},
progress: function() {},
promise: function() {},
reject: function() {},
rejectWith: function() {},
resolve: function() {},
resolveWith: function() {},
state: function() {},
then: function() {} }
</code></pre>
</section>
<section>
<h2>promise()</h2>
<pre><code>
// A read-only version of the deferred object;
// returned from a jQuery $.ajax() call.
def.promise();
> { always: function() {},
done: function() {},
fail: function() {},
pipe: function() {},
progress: function() {},
promise: function() {},
state: function() {},
then: function() {} }
</code></pre>
</section>
</section>
<section>
<section>
<h1>The Writers</h1>
</section>
<section>
<h2>resolve()</h2>
<pre><code>
var deferred = $.Deferred();
deferred.promise().state();
> "pending"
deferred.resolve();
deferred.promise().state();
> "resolved"
</code></pre>
</section>
<section>
<h2>reject()</h2>
<pre><code>
var deferred = $.Deferred();
deferred.promise().state();
> "pending"
deferred.reject();
deferred.promise().state();
> "rejected"
</code></pre>
</section>
<section>
<h2>pipe()</h2>
<pre><code>
var deferred = $.Deferred();
deferred.pipe(
function(resp) {
console.log("I filter done responses", resp);
},
function(resp) {
console.log("I filter fail responses", resp);
},
function(resp) {
console.log("I filter progress responses", resp);
}
);
</code></pre>
</section>
</section>
<section>
<section>
<h1>The Readers</h1>
</section>
<section>
<h2>done()</h2>
<pre><code>
var deferred = $.Deferred();
deferred.resolve();
deferred.done(function() {
console.log("I get called when things go well.");
});
</code></pre>
</section>
<section>
<h2>fail()</h2>
<pre><code>
var deferred = $.Deferred();
deferred.reject();
deferred.fail(function() {
console.log("I get called when things fall apart.");
});
</code></pre>
</section>
<section>
<h2>always()</h2>
<pre><code>
var deferred = $.Deferred();
deferred.resolve();
deferred.always(function() {
console.log("I'm so popular, I get called no matter what.");
});
</code></pre>
</section>
<section>
<h2>then()</h2>
<pre><code>
var deferred = $.Deferred();
// Shorthand for done, fail, and always.
deferred.then(
function(resp) {
console.log("I'm a done callback!", resp);
},
function(resp) {
console.log("I'm a fail callback.", resp);
},
function(resp) {
console.log("I'm an always callback.", resp);
}
);
</code></pre>
</section>
</section>
<section>
<section>
<h1>How does it solve our problems?</h1>
</section>
<section data-state='alert'>
<h2>Sequencing mess</h2>
<pre><code>
$.get('api1/data', function(resp1) {
// Next that depended on the first response.
$.get('api2/data', function(resp2) {
// Next request that depended on the second response.
$.get('api3/data', function(resp3) {
// Next request that depended on the third response.
});
});
});
</code></pre>
</section>
<section>
<h2>Deferred sequencing</h2>
<pre><code>
var req1 = $.get('api1/data');
var req2 = $.get('api2/data');
var req3 = $.get('api3/data');
req1.then(function(req1Data) {
return req2;
}).then(function(req2Data) {
return req3;
});
req2.then(function(req2Data) {
// Do something somewhere entirely different.
});
</code></pre>
</section>
<section data-state='alert'>
<h2>Ugly Parallel Requests</h2>
<pre><code>
$.get('api1/data', function(resp1) { trackMe(); });
$.get('api2/data', function(resp2) { trackMe(); });
$.get('api3/data', function(resp3) { trackMe(); });
var trackedCount = 0;
function trackMe() {
++trackedCount;
if (trackedCount === 3) {
doSomethingThatNeededAllThree();
}
}
</code></pre>
</section>
<section>
<h2>Deferred Parallelization</h2>
<pre><code>
$.when(
$.get('api1/data'),
$.get('api2/data'),
$.get('api3/data'),
{ key: 'value' }
).done();
</code></pre>
</section>
<section>
<h2>Filtered responses</h2>
<pre><code>
var getArticleByHeadline = function(query) {
return $.ajax({ url: 'api/articles' })
.pipe(function(data) {
// Filter article headlines by query.
});
}
getArticleByHeadline('wins election').done(function(articles) {
// Do with the articles.
});
</code></pre>
</section>
</section>
<section>
<section>
<h1>Summary</h1>
<ul>
<li class='fragment'>Really good when you need to guarantee something else has completed before proceeding, either one after another or all together.</li>
<li class='fragment'>Improves code composition:
<ul>
<li class='fragment'>flat</li>
<li class='fragment'>decoupled</li>
</ul>
</li>
</ul>
</section>
</section>
<section>
<section>
<h2>Resources</h2>
<ul>
<li><a href="http://www.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript">Callbacks, promises, and coroutines</a></li>
<li><a href="https://github.com/kriskowal/q/wiki/Coming-from-jQuery">Q.js from jQuery</a></li>
<li><a href="http://msdn.microsoft.com/en-us/magazine/gg723713.aspx">Creating Responsive Applications Using jQuery Deferred and Promises</a></li>
<li><a href="http://www.html5rocks.com/en/tutorials/async/deferred/">ASYNCH JS: THE POWER OF $.DEFERRED</a></li>
<li><a href="http://idlebrains.org/tutorials/jquery/deferred-and-promise-methods/jquery-exploring-deferred-and-promise/">jQuery : Exploring Deferred and Promise methods</a></li>
</ul>
</section>
</section>
</div>
</div>
<script src="lib/js/head.min.js"></script>
<script src="js/reveal.min.js"></script>
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
theme: 'beige', // available themes are in /css/theme
transition: 'linear', // default/cube/page/concave/zoom/linear/none
// Optional libraries used to extend on reveal.js
dependencies: [
{ src: 'lib/js/highlight.js', async: true, callback: function() { window.hljs.initHighlightingOnLoad(); } },
{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'lib/js/showdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'lib/js/data-markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'lib/js/jquery-1.8.2.js' },
{ src: 'plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: 'plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
]
});
</script>
</body>
</html>
Jump to Line
Something went wrong with that request. Please try again.