Codebase list node-slide / 48db396
Imported Upstream version 1.1.4 Jérémy Lal 11 years ago
3 changed file(s) with 157 addition(s) and 18 deletion(s). Raw diff Collapse all Expand all
0 Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
1 All rights reserved.
2
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation
5 files (the "Software"), to deal in the Software without
6 restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following
10 conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
0 # Slide - a tiny flow control library
0 # Controlling Flow: callbacks are easy
11
2 Callbacks are simple and easy if you keep the pattern consistent.
2 ## What's actually hard?
33
4 Check out the [slide presentation](http://github.com/isaacs/slide-flow-control/raw/master/nodejs-controlling-flow.pdf).
4 - Doing a bunch of things in a specific order.
5 - Knowing when stuff is done.
6 - Handling failures.
7 - Breaking up functionality into parts (avoid nested inline callbacks)
58
6 You'll laugh when you see how little code is actually in this thing.
7 It's so not-enterprisey, you won't believe it. It does almost nothing,
8 but it's super handy.
99
10 I actually use an earlier version of this util in
11 [a real world program](http://npmjs.org/).
10 ## Common Mistakes
1211
13 ## Installation
12 - Abandoning convention and consistency.
13 - Putting all callbacks inline.
14 - Using libraries without grokking them.
15 - Trying to make async code look sync.
1416
15 Just copy the files into your project, and use them that way, or
16 you can do this:
17 ## Define Conventions
1718
18 npm install slide
19 - Two kinds of functions: *actors* take action, *callbacks* get results.
20 - Essentially the continuation pattern. Resulting code *looks* similar
21 to fibers, but is *much* simpler to implement.
22 - Node works this way in the lowlevel APIs already, and it's very flexible.
1923
20 and then:
24 ## Callbacks
2125
22 var asyncMap = require("slide").asyncMap
23 , chain = require("slide").chain
24 // use the power!
26 - Simple responders
27 - Must always be prepared to handle errors, that's why it's the first argument.
28 - Often inline anonymous, but not always.
29 - Can trap and call other callbacks with modified data, or pass errors upwards.
2530
26 Enjoy!
31 ## Actors
32
33 - Last argument is a callback.
34 - If any error occurs, and can't be handled, pass it to the callback and return.
35 - Must not throw. Return value ignored.
36 - return x ==> return cb(null, x)
37 - throw er ==> return cb(er)
38
39 ```javascript
40 // return true if a path is either
41 // a symlink or a directory.
42 function isLinkOrDir (path, cb) {
43 fs.lstat(path, function (er, s) {
44 if (er) return cb(er)
45 return cb(null, s.isDirectory() || s.isSymbolicLink())
46 })
47 }
48 ```
49
50 # asyncMap
51
52 ## Usecases
53
54 - I have a list of 10 files, and need to read all of them, and then continue when they're all done.
55 - I have a dozen URLs, and need to fetch them all, and then continue when they're all done.
56 - I have 4 connected users, and need to send a message to all of them, and then continue when that's done.
57 - 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.
58
59
60 ## Solution
61
62 ```javascript
63 var asyncMap = require("slide").asyncMap
64 function writeFiles (files, what, cb) {
65 asyncMap(files, function (f, cb) {
66 fs.writeFile(f, what, cb)
67 }, cb)
68 }
69 writeFiles([my, file, list], "foo", cb)
70 ```
71
72 # chain
73
74 ## Usecases
75
76 - I have to do a bunch of things, in order. Get db credentials out of a file,
77 read the data from the db, write that data to another file.
78 - If anything fails, do not continue.
79 - I still have to provide an array of functions, which is a lot of boilerplate,
80 and a pita if your functions take args like
81
82 ```javascript
83 function (cb) {
84 blah(a, b, c, cb)
85 }
86 ```
87
88 - Results are discarded, which is a bit lame.
89 - No way to branch.
90
91 ## Solution
92
93 - reduces boilerplate by converting an array of [fn, args] to an actor
94 that takes no arguments (except cb)
95 - A bit like Function#bind, but tailored for our use-case.
96 - bindActor(obj, "method", a, b, c)
97 - bindActor(fn, a, b, c)
98 - bindActor(obj, fn, a, b, c)
99 - branching, skipping over falsey arguments
100
101 ```javascript
102 chain([
103 doThing && [thing, a, b, c]
104 , isFoo && [doFoo, "foo"]
105 , subChain && [chain, [one, two]]
106 ], cb)
107 ```
108
109 - tracking results: results are stored in an optional array passed as argument,
110 last result is always in results[results.length - 1].
111 - treat chain.first and chain.last as placeholders for the first/last
112 result up until that point.
113
114
115 ## Non-trivial example
116
117 - Read number files in a directory
118 - Add the results together
119 - Ping a web service with the result
120 - Write the response to a file
121 - Delete the number files
122
123 ```javascript
124 var chain = require("slide").chain
125 function myProgram (cb) {
126 var res = [], last = chain.last, first = chain.first
127 chain([
128 [fs, "readdir", "the-directory"]
129 , [readFiles, "the-directory", last]
130 , [sum, last]
131 , [ping, "POST", "example.com", 80, "/foo", last]
132 , [fs, "writeFile", "result.txt", last]
133 , [rmFiles, "./the-directory", first]
134 ], res, cb)
135 }
136 ```
137
138 # Conclusion: Convention Profits
139
140 - Consistent API from top to bottom.
141 - Sneak in at any point to inject functionality. Testable, reusable, ...
142 - When ruby and python users whine, you can smile condescendingly.
00 {
11 "name": "slide",
2 "version": "1.1.3",
2 "version": "1.1.4",
33 "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
44 "contributors": [
55 "S. Sriram <ssriram@gmail.com> (http://www.565labs.com)"