-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4f0a476
Showing
24 changed files
with
4,044 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, target-densityDpi=medium-dpi"/><meta content="True" name="HandheldFriendly"/><title>The simplest example</title><link rel="shortcut icon" href="/ico/favicon.ico"/><link rel="stylesheet" href="/styles/style.css"/><link rel="stylesheet" href="/styles/nuggets.css"/><link rel="stylesheet" href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css"/></head><body><div class="main"><a href="https://github.com/promise-nuggets/promise-nuggets.github.io"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"/></a><h1><a class="back" href="/">↩</a><span>The simplest example</span></h1><div class="content"><p>Whats the main difference between callback-based functions and promise-based | ||
functions?</p> | ||
<p>The first call the callback with the error and the result:</p> | ||
<pre><code class="language-js">fs.readFile(path, function(error, content) { | ||
// handle error or do something with content | ||
})</code></pre> | ||
<p>The second return promises. We can attach two callbacks - one for the value, | ||
another to handle the error:</p> | ||
<pre><code class="language-js">fs.readFileAsync(path).done(function(content) { | ||
// do something with content | ||
}, function(error) { | ||
// handle error | ||
})</code></pre> | ||
<h2 id="notes">Notes</h2> | ||
<p>Whats going on here?</p> | ||
<p><code>fs.readFileAsync(file)</code> starts a file reading operation. | ||
That operation is not yet complete at the point when readFile returns. This | ||
means we can't return the file content.</p> | ||
<p>But we can still return something: we can return the reading operation itself. | ||
And that operation is represented by a promise.</p> | ||
<p>It's is sort of like a single-value stream:</p> | ||
<pre><code class="language-js">net.connect(port).on('data', function(res) { | ||
doStuffWith(res); | ||
}).on('error', function(err) { | ||
handleError(); | ||
});</code></pre> | ||
<p>But there are also some important differences which are going to be covered | ||
later on.</p> | ||
</div></div><script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"></script><script>function $(q) { return [].slice.call(document.querySelectorAll(q)); } | ||
$('code').forEach(function(el) { el.className += ' prettyprint'; }); | ||
prettyPrint();</script></body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<p>Creating simple functions is easy.</p> | ||
<h4 id="callbacks">Callbacks</h4> | ||
<p>To create a callback-taking function, add a callback argument to your function. | ||
Then you can pass the callback to another callback-taking function.</p> | ||
<pre><code class="language-js">function readMyFile(callback) { | ||
fs.readFile('myfile.txt', callback); | ||
}</code></pre> | ||
<h4 id="promises">Promises</h4> | ||
<p>To create a promise-based function, simply return the promise as a result.</p> | ||
<pre><code class="language-js">function readMyFile() { | ||
return fs.readFileAsync('myfile.txt'); | ||
}</code></pre> | ||
<p>But what if you want to do additional processing? Then you'll also need to | ||
<a href="03-power-of-then-sync-processing.html">create your own callback, or use the power of <code>.then()</code></a>.</p> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, target-densityDpi=medium-dpi"/><meta content="True" name="HandheldFriendly"/><title>Creating new functions</title><link rel="shortcut icon" href="/ico/favicon.ico"/><link rel="stylesheet" href="/styles/style.css"/><link rel="stylesheet" href="/styles/nuggets.css"/><link rel="stylesheet" href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css"/></head><body><div class="main"><a href="https://github.com/promise-nuggets/promise-nuggets.github.io"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"/></a><h1><a class="back" href="/">↩</a><span>Creating new functions</span></h1><div class="content"><p>Creating simple functions is easy.</p> | ||
<h4 id="callbacks">Callbacks</h4> | ||
<p>To create a callback-taking function, add a callback argument to your function. | ||
Then you can pass the callback to another callback-taking function.</p> | ||
<pre><code class="language-js">function readMyFile(callback) { | ||
fs.readFile('myfile.txt', callback); | ||
}</code></pre> | ||
<h4 id="promises">Promises</h4> | ||
<p>To create a promise-based function, simply return the promise as a result.</p> | ||
<pre><code class="language-js">function readMyFile() { | ||
return fs.readFileAsync('myfile.txt'); | ||
}</code></pre> | ||
<p>But what if you want to do additional processing? Then you'll also need to | ||
<a href="03-power-of-then-sync-processing.html">create your own callback, or use the power of <code>.then()</code></a>.</p> | ||
</div></div><script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"></script><script>function $(q) { return [].slice.call(document.querySelectorAll(q)); } | ||
$('code').forEach(function(el) { el.className += ' prettyprint'; }); | ||
prettyPrint();</script></body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, target-densityDpi=medium-dpi"/><meta content="True" name="HandheldFriendly"/><title>The power of then - sync processing</title><link rel="shortcut icon" href="/ico/favicon.ico"/><link rel="stylesheet" href="/styles/style.css"/><link rel="stylesheet" href="/styles/nuggets.css"/><link rel="stylesheet" href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css"/></head><body><div class="main"><a href="https://github.com/promise-nuggets/promise-nuggets.github.io"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"/></a><h1><a class="back" href="/">↩</a><span>The power of then - sync processing</span></h1><div class="content"><p>It's easy to <a href="02-creating-new-functions.html">just pass the callback or return a promise</a> | ||
if we don't need to do other stuff to the result.</p> | ||
<p>But what if we wanted to do additional processing? What if we want to read a | ||
single line of a file? Then we'll need to add some code to split the file into | ||
lines and get the specified line. Let's see how we can do that.</p> | ||
<h4 id="callbacks">Callbacks</h4> | ||
<p>To do this with callbacks, we'll pass our custom callback that does the | ||
splitting.</p> | ||
<p>The callback bails-out if there was an error reading the file, | ||
otherwise proceeds to split the content and call the original callback with | ||
the line content:</p> | ||
<pre><code class="language-js">function readLine(file, line, callback) { | ||
fs.readFile(file, function process(err, content) { | ||
if (err) return callback(err); | ||
callback(null, content.toString().split('\n')[line]); | ||
}); | ||
} | ||
readLine('myfile.txt', 2, function(err, line) { | ||
// handle error or use line | ||
});</code></pre> | ||
<h4 id="promises">Promises</h4> | ||
<p>To create a promise-based function we can use another promise method called | ||
<code>.then()</code>. It works exactly the same as <code>.done()</code>, but also returns a promise | ||
for the value returned inside its callbacks.</p> | ||
<p>We can simply return the line from inside the first <code>.then</code> callback. We get a | ||
promise for that line outside of the callback (which we return from the | ||
function)</p> | ||
<pre><code class="language-js">function readLine(file, line) { | ||
return fs.readFileAsync(file).then(function(res) { | ||
return res.toString().split('\n')[line]; | ||
}); | ||
} | ||
readLine(file, line).done(function(line) { | ||
// use line | ||
}, function(err) { | ||
// handle error | ||
});</code></pre> | ||
<p>When you call a promise's <code>.then</code> function, a new promise is created and returned | ||
by <code>.then</code>. It's a promise to apply all the operations inside the then callback | ||
after the original async operation completes, and return the result.</p> | ||
<h2 id="notes">Notes</h2> | ||
<p>In the callback example, we must explicitly handle the error. Since we can't | ||
deal with that error there, we must call the passed callback to pass that error.</p> | ||
<p>In the promise example, we can skip the error handling function. If we do that, | ||
the error will automatically propagate with the returned promise for a line. | ||
Yes, that means that you don't have to write <code>if (err) return callback(err)</code> | ||
anymore - promises do the equivalent of that by default.</p> | ||
<p>Another useful way to think of <code>done</code> vs <code>then</code>: <code>Promise.done()</code> is the | ||
equivalent of <code>Array.forEach</code> while <code>Promise.then()</code> is the equivalent of | ||
<code>Array.map</code>. You use the first when you don't want to create a new promise, and | ||
the second when you do.</p> | ||
</div></div><script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"></script><script>function $(q) { return [].slice.call(document.querySelectorAll(q)); } | ||
$('code').forEach(function(el) { el.className += ' prettyprint'; }); | ||
prettyPrint();</script></body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, target-densityDpi=medium-dpi"/><meta content="True" name="HandheldFriendly"/><title>The power of then - async operations</title><link rel="shortcut icon" href="/ico/favicon.ico"/><link rel="stylesheet" href="/styles/style.css"/><link rel="stylesheet" href="/styles/nuggets.css"/><link rel="stylesheet" href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css"/></head><body><div class="main"><a href="https://github.com/promise-nuggets/promise-nuggets.github.io"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"/></a><h1><a class="back" href="/">↩</a><span>The power of then - async operations</span></h1><div class="content"><p>In the <a href="03-power-of-then-sync-processing.html">previous example</a> we learned | ||
how to apply sync transformations to the result. But what if we need to do | ||
another async operation instead?</p> | ||
<p>For example, what if we want to fetch the user from a database, then fetch all | ||
of his friends?</p> | ||
<h4 id="callbacks">Callbacks</h4> | ||
<p>With callbacks we can nest the friend fetching operation and pass the original | ||
callback.</p> | ||
<pre><code class="language-js">function getUserFriends(id, callback) { | ||
User.findOne({id: id}, function(err, user) { | ||
if (err) return callback(err); | ||
User.find({id: {$in: user.friends}}, callback); | ||
}); | ||
}</code></pre> | ||
<h4 id="promises">Promises</h4> | ||
<p>With promises, we can return the promise for the fetched friends from inside | ||
<code>.then</code></p> | ||
<pre><code class="language-js">function getUserFriends(id) { | ||
return User.findOne({id: id}).then(function(user) { | ||
return User.find({id: {$in: user.friends}}); | ||
}); | ||
}</code></pre> | ||
<p>And we get a promise for the fetched friends outside of <code>.then</code>.</p> | ||
<h2 id="notes">Notes</h2> | ||
<p>How come this works? If we return a promise from <code>.then()</code> won't we get a | ||
promise for a promise inside <code>.then()</code>?</p> | ||
<p>The answer is no. When <code>.then()</code> sees that we have returned a promise, it will | ||
also try to "unpack" it to get to an actual value. As long as the unpacking | ||
results with another promise, <code>.then()</code> will continue to unpack them.</p> | ||
<p>In the callback example, we must explicitly handle the error. Since we can't | ||
deal with that error there, we must call the passed callback to pass that error.</p> | ||
<p>In the promise example, if at any point <code>.then</code> encounters a promise that | ||
resolved with an error, it will stop unpacking and propagate that error through | ||
the returned promise.</p> | ||
</div></div><script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"></script><script>function $(q) { return [].slice.call(document.querySelectorAll(q)); } | ||
$('code').forEach(function(el) { el.className += ' prettyprint'; }); | ||
prettyPrint();</script></body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, target-densityDpi=medium-dpi"/><meta content="True" name="HandheldFriendly"/><title>The first relief - when sync becomes async</title><link rel="shortcut icon" href="/ico/favicon.ico"/><link rel="stylesheet" href="/styles/style.css"/><link rel="stylesheet" href="/styles/nuggets.css"/><link rel="stylesheet" href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css"/></head><body><div class="main"><a href="https://github.com/promise-nuggets/promise-nuggets.github.io"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"/></a><h1><a class="back" href="/">↩</a><span>The first relief - when sync becomes async</span></h1><div class="content"><p>I hear you. Promise code doesn't look too different from regular node callbacks | ||
or event emitters, except that you use a second callback for the error. And | ||
you're still not convinced that there is any benefit to using <code>.then()</code> to | ||
create new promises.</p> | ||
<p>Okay then. Lets take things to the next level.</p> | ||
<p>Using <code>.then()</code>, you can attach the callbacks later if you want.</p> | ||
<p>For example <code>fs.readFileAsync(file)</code> returns a promise. That promise is a value, | ||
so you can put that in a var, or return it from a function:</p> | ||
<pre><code class="language-js">var filePromise = fs.readFileAsync(file); | ||
filePromise.done(function(res) { ... }, function(err) {});</code></pre> | ||
<p>Okay, that's still not much of an improvement. How about this then? You can | ||
attach more than one callback to a promise if you like:</p> | ||
<pre><code class="language-js">filePromise.done(function(res) { uploadData(url, res); }); | ||
filePromise.done(function(res) { saveLocal(url, res); }, | ||
function(err), {}); | ||
// etc</code></pre> | ||
<p>Hey, this is beginning to look more and more like streams - they too can be | ||
piped to multiple destinations. But unlike streams, you can attach more | ||
callbacks and get the value even <em>after</em> the file reading operation completes.</p> | ||
<p>The promise will cache the value, and call your callback right after the next | ||
tick. The file reading operation is always done only once - no need to repeat | ||
it.</p> | ||
<p>All of this makes it easier when you need to switch code that was previously | ||
sync but had to become async for some reason.</p> | ||
<p>For example: imagine that you need to get some stats about two file versions</p> | ||
<ul> | ||
<li>like number of lines in both versions and the number of lines in their diff:</li> | ||
</ul> | ||
<pre><code class="language-js">var first = files[0], other = files[1]; | ||
var diffFirstOther = diff(first, other); | ||
|
||
var firstLines = first.split('\n').length, | ||
otherLines = other.split('\n').length; | ||
|
||
var diffLines = diffFirstOther.split('\n'); | ||
|
||
var result = { | ||
first: firstLines, | ||
other: otherLines, | ||
diff: diffLines | ||
};</code></pre> | ||
<p>Later on, you figure out that the <code>diff()</code> function is kind of expensive in | ||
terms of CPU power, so you want it to run in another process. Lets see what | ||
are your options:</p> | ||
<h4 id="callbacks">Callbacks</h4> | ||
<p>You need to change the function <code>diff</code> to take a callback, and you move | ||
the diffLines calculation inside. So far so good:</p> | ||
<pre><code class="language-js">var first = files[0], other = files[1]; | ||
diff(first, other, function(err, diffFirstOther) { | ||
var diffLines = diffFirstOther.split('\n'); | ||
}); | ||
</code></pre> | ||
<p>But wait, now the result needs to be inside that callback too.</p> | ||
<pre><code class="language-js">var first = files[0], other = files[1]; | ||
diff(first, other, function(err, diffFirstOther) { | ||
var diffLines = diffFirstOther.split('\n'); | ||
var result = { | ||
first: firstLines, | ||
other: otherLines, | ||
diff: diffLines | ||
}; | ||
}); | ||
var firstLines = first.split('\n').length, | ||
otherLines = other.split('\n').length; | ||
</code></pre> | ||
<p>This works but its horribly unintuitive because it looks like you're using | ||
the variables <code>firstLines</code> and <code>otherLines</code> before they are available. So you | ||
decide its best to move those lines at the top:</p> | ||
<pre><code class="language-js">var first = files[0], other = files[1]; | ||
var firstLines = first.split('\n').length, | ||
otherLines = other.split('\n').length; | ||
|
||
diff(first, other, function(err, diffFirstOther) { | ||
var diffLines = diffFirstOther.split('\n'); | ||
var result = { | ||
first: firstLines, | ||
other: otherLines, | ||
diff: diffLines | ||
}; | ||
});</code></pre> | ||
<h4 id="promises">Promises</h4> | ||
<p>With promises our code can stay almost exactly the same. No need to move things | ||
around to make them more intuitive. No need to figure out whether we need to | ||
stuff other lines inside our callback because they have a dependency on the | ||
result of that callback. Instead, we combine:</p> | ||
<ul> | ||
<li>the ability to attach callbacks whenever we want,</li> | ||
<li>the power to create new promises by returning from <code>.then()</code>, and</li> | ||
<li>the use of promise values to replace the original values</li> | ||
</ul> | ||
<pre><code class="language-js">var first = files[0], other = files[1]; | ||
var pDiffFirstOther = diff(first, other); | ||
|
||
var firstLines = first.split('\n').length, | ||
otherLines = other.split('\n').length; | ||
|
||
var pDiffLines = pDiffFirstOther.then(function(diff) { | ||
return diff.split('\n'); | ||
}); | ||
|
||
var pResult = pDiffLines.then(function(diffLines) { | ||
return { | ||
first: firstLines, | ||
other: otherLines, | ||
diff: diffLines | ||
}; | ||
});</code></pre> | ||
<p>Everything is exactly the same, except that we now have promises instead of | ||
values.</p> | ||
<p>Whenever we want to do some extra sync (or async) processing on these | ||
promises, we can unpack them with <code>.then()</code> and apply our transformation inside | ||
the callback, then return a new value which will be packed in a new promise. | ||
No need to move code around to make it fit under the same callback.</p> | ||
<p>That's pretty great, isn't it? But <a href="06-safety-of-then-exceptions.html">wait 'til you see what happens with | ||
errors</a></p> | ||
</div></div><script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"></script><script>function $(q) { return [].slice.call(document.querySelectorAll(q)); } | ||
$('code').forEach(function(el) { el.className += ' prettyprint'; }); | ||
prettyPrint();</script></body></html> |
Oops, something went wrong.