--- /dev/null
+# Controlling Flow: callbacks are easy
+
+## What's actually hard?
+
+- Doing a bunch of things in a specific order.
+- Knowing when stuff is done.
+- Handling failures.
+- Breaking up functionality into parts (avoid nested inline callbacks)
+
+
+## Common Mistakes
+
+- Abandoning convention and consistency.
+- Putting all callbacks inline.
+- Using libraries without grokking them.
+- Trying to make async code look sync.
+
+## Define Conventions
+
+- Two kinds of functions: *actors* take action, *callbacks* get results.
+- Essentially the continuation pattern. Resulting code *looks* similar
+ to fibers, but is *much* simpler to implement.
+- Node works this way in the lowlevel APIs already, and it's very flexible.
+
+## Callbacks
+
+- Simple responders
+- Must always be prepared to handle errors, that's why it's the first argument.
+- Often inline anonymous, but not always.
+- Can trap and call other callbacks with modified data, or pass errors upwards.
+
+## Actors
+
+- Last argument is a callback.
+- If any error occurs, and can't be handled, pass it to the callback and return.
+- Must not throw. Return value ignored.
+- return x ==> return cb(null, x)
+- throw er ==> return cb(er)
+
+```javascript
+// return true if a path is either
+// a symlink or a directory.
+function isLinkOrDir (path, cb) {
+ fs.lstat(path, function (er, s) {
+ if (er) return cb(er)
+ return cb(null, s.isDirectory() || s.isSymbolicLink())
+ })
+}
+```
+
+# asyncMap
+
+## Usecases
+
+- I have a list of 10 files, and need to read all of them, and then continue when they're all done.
+- I have a dozen URLs, and need to fetch them all, and then continue when they're all done.
+- I have 4 connected users, and need to send a message to all of them, and then continue when that's done.
+- I have a list of n things, and I need to dosomething with all of them, in parallel, and get the results once they're all complete.
+
+
+## Solution
+
+```javascript
+var asyncMap = require("slide").asyncMap
+function writeFiles (files, what, cb) {
+ asyncMap(files, function (f, cb) {
+ fs.writeFile(f, what, cb)
+ }, cb)
+}
+writeFiles([my, file, list], "foo", cb)
+```
+
+# chain
+
+## Usecases
+
+- I have to do a bunch of things, in order. Get db credentials out of a file,
+ read the data from the db, write that data to another file.
+- If anything fails, do not continue.
+- I still have to provide an array of functions, which is a lot of boilerplate,
+ and a pita if your functions take args like
+
+```javascript
+function (cb) {
+ blah(a, b, c, cb)
+}
+```
+
+- Results are discarded, which is a bit lame.
+- No way to branch.
+
+## Solution
+
+- reduces boilerplate by converting an array of [fn, args] to an actor
+ that takes no arguments (except cb)
+- A bit like Function#bind, but tailored for our use-case.
+- bindActor(obj, "method", a, b, c)
+- bindActor(fn, a, b, c)
+- bindActor(obj, fn, a, b, c)
+- branching, skipping over falsey arguments
+
+```javascript
+chain([
+ doThing && [thing, a, b, c]
+, isFoo && [doFoo, "foo"]
+, subChain && [chain, [one, two]]
+], cb)
+```
+
+- tracking results: results are stored in an optional array passed as argument,
+ last result is always in results[results.length - 1].
+- treat chain.first and chain.last as placeholders for the first/last
+ result up until that point.
+
+
+## Non-trivial example
+
+- Read number files in a directory
+- Add the results together
+- Ping a web service with the result
+- Write the response to a file
+- Delete the number files
+
+```javascript
+var chain = require("slide").chain
+function myProgram (cb) {
+ var res = [], last = chain.last, first = chain.first
+ chain([
+ [fs, "readdir", "the-directory"]
+ , [readFiles, "the-directory", last]
+ , [sum, last]
+ , [ping, "POST", "example.com", 80, "/foo", last]
+ , [fs, "writeFile", "result.txt", last]
+ , [rmFiles, "./the-directory", first]
+ ], res, cb)
+}
+```
+
+# Conclusion: Convention Profits
+
+- Consistent API from top to bottom.
+- Sneak in at any point to inject functionality. Testable, reusable, ...
+- When ruby and python users whine, you can smile condescendingly.