mirror of
https://github.com/zhigang1992/npm.git
synced 2026-04-28 20:15:33 +08:00
slide@1.1.4
This commit is contained in:
1
node_modules/slide/.npmignore
generated
vendored
1
node_modules/slide/.npmignore
generated
vendored
@@ -1 +0,0 @@
|
||||
*.pdf
|
||||
153
node_modules/slide/README.md
generated
vendored
153
node_modules/slide/README.md
generated
vendored
@@ -1,32 +1,143 @@
|
||||
# Slide - a tiny flow control library
|
||||
# Controlling Flow: callbacks are easy
|
||||
|
||||
Callbacks are simple and easy if you keep the pattern consistent.
|
||||
## What's actually hard?
|
||||
|
||||
Check out the [slide
|
||||
presentation](http://github.com/isaacs/slide-flow-control/raw/master/nodejs-controlling-flow.pdf),
|
||||
or the [blog post](http://howto.no.de/flow-control-in-npm).
|
||||
- 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)
|
||||
|
||||
You'll laugh when you see how little code is actually in this thing.
|
||||
It's so not-enterprisey, you won't believe it. It does almost nothing,
|
||||
but it's super handy.
|
||||
|
||||
I use this util in [a real world program](http://npmjs.org/).
|
||||
## Common Mistakes
|
||||
|
||||
You should use it as an example of how to write your own flow control
|
||||
utilities. You'll never fully appreciate a flow control lib that you
|
||||
didn't write yourself.
|
||||
- Abandoning convention and consistency.
|
||||
- Putting all callbacks inline.
|
||||
- Using libraries without grokking them.
|
||||
- Trying to make async code look sync.
|
||||
|
||||
## Installation
|
||||
## Define Conventions
|
||||
|
||||
Just copy the files into your project, and use them that way, or
|
||||
you can do this:
|
||||
- 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.
|
||||
|
||||
npm install slide
|
||||
## Callbacks
|
||||
|
||||
and then:
|
||||
- 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.
|
||||
|
||||
var asyncMap = require("slide").asyncMap
|
||||
, chain = require("slide").chain
|
||||
// use the power!
|
||||
## Actors
|
||||
|
||||
Enjoy!
|
||||
- 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.
|
||||
|
||||
BIN
node_modules/slide/nodejs-controlling-flow.pdf
generated
vendored
BIN
node_modules/slide/nodejs-controlling-flow.pdf
generated
vendored
Binary file not shown.
23
node_modules/slide/package.json
generated
vendored
23
node_modules/slide/package.json
generated
vendored
@@ -1,9 +1,17 @@
|
||||
{
|
||||
"name": "slide",
|
||||
"version": "1.1.3",
|
||||
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
|
||||
"version": "1.1.4",
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me",
|
||||
"url": "http://blog.izs.me/"
|
||||
},
|
||||
"contributors": [
|
||||
"S. Sriram <ssriram@gmail.com> (http://www.565labs.com)"
|
||||
{
|
||||
"name": "S. Sriram",
|
||||
"email": "ssriram@gmail.com",
|
||||
"url": "http://www.565labs.com"
|
||||
}
|
||||
],
|
||||
"description": "A flow control lib small enough to fit on in a slide presentation. Derived live at Oak.JS",
|
||||
"main": "./lib/slide.js",
|
||||
@@ -15,5 +23,12 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/slide-flow-control.git"
|
||||
}
|
||||
},
|
||||
"readme": "# Controlling Flow: callbacks are easy\n\n## What's actually hard?\n\n- Doing a bunch of things in a specific order.\n- Knowing when stuff is done.\n- Handling failures.\n- Breaking up functionality into parts (avoid nested inline callbacks)\n\n\n## Common Mistakes\n\n- Abandoning convention and consistency.\n- Putting all callbacks inline.\n- Using libraries without grokking them.\n- Trying to make async code look sync.\n\n## Define Conventions\n\n- Two kinds of functions: *actors* take action, *callbacks* get results.\n- Essentially the continuation pattern. Resulting code *looks* similar\n to fibers, but is *much* simpler to implement.\n- Node works this way in the lowlevel APIs already, and it's very flexible.\n\n## Callbacks\n\n- Simple responders\n- Must always be prepared to handle errors, that's why it's the first argument.\n- Often inline anonymous, but not always.\n- Can trap and call other callbacks with modified data, or pass errors upwards.\n\n## Actors\n\n- Last argument is a callback.\n- If any error occurs, and can't be handled, pass it to the callback and return.\n- Must not throw. Return value ignored.\n- return x ==> return cb(null, x)\n- throw er ==> return cb(er)\n\n```javascript\n// return true if a path is either\n// a symlink or a directory.\nfunction isLinkOrDir (path, cb) {\n fs.lstat(path, function (er, s) {\n if (er) return cb(er)\n return cb(null, s.isDirectory() || s.isSymbolicLink())\n })\n}\n```\n\n# asyncMap\n\n## Usecases\n\n- I have a list of 10 files, and need to read all of them, and then continue when they're all done.\n- I have a dozen URLs, and need to fetch them all, and then continue when they're all done.\n- I have 4 connected users, and need to send a message to all of them, and then continue when that's done.\n- 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.\n\n\n## Solution\n\n```javascript\nvar asyncMap = require(\"slide\").asyncMap\nfunction writeFiles (files, what, cb) {\n asyncMap(files, function (f, cb) {\n fs.writeFile(f, what, cb)\n }, cb)\n}\nwriteFiles([my, file, list], \"foo\", cb)\n```\n\n# chain\n\n## Usecases\n\n- I have to do a bunch of things, in order. Get db credentials out of a file,\n read the data from the db, write that data to another file.\n- If anything fails, do not continue.\n- I still have to provide an array of functions, which is a lot of boilerplate,\n and a pita if your functions take args like\n\n```javascript\nfunction (cb) {\n blah(a, b, c, cb)\n}\n```\n\n- Results are discarded, which is a bit lame.\n- No way to branch.\n\n## Solution\n\n- reduces boilerplate by converting an array of [fn, args] to an actor\n that takes no arguments (except cb)\n- A bit like Function#bind, but tailored for our use-case.\n- bindActor(obj, \"method\", a, b, c)\n- bindActor(fn, a, b, c)\n- bindActor(obj, fn, a, b, c)\n- branching, skipping over falsey arguments\n\n```javascript\nchain([\n doThing && [thing, a, b, c]\n, isFoo && [doFoo, \"foo\"]\n, subChain && [chain, [one, two]]\n], cb)\n```\n\n- tracking results: results are stored in an optional array passed as argument,\n last result is always in results[results.length - 1].\n- treat chain.first and chain.last as placeholders for the first/last\n result up until that point.\n\n\n## Non-trivial example\n\n- Read number files in a directory\n- Add the results together\n- Ping a web service with the result\n- Write the response to a file\n- Delete the number files\n\n```javascript\nvar chain = require(\"slide\").chain\nfunction myProgram (cb) {\n var res = [], last = chain.last, first = chain.first\n chain([\n [fs, \"readdir\", \"the-directory\"]\n , [readFiles, \"the-directory\", last]\n , [sum, last]\n , [ping, \"POST\", \"example.com\", 80, \"/foo\", last]\n , [fs, \"writeFile\", \"result.txt\", last]\n , [rmFiles, \"./the-directory\", first]\n ], res, cb)\n}\n```\n\n# Conclusion: Convention Profits\n\n- Consistent API from top to bottom.\n- Sneak in at any point to inject functionality. Testable, reusable, ...\n- When ruby and python users whine, you can smile condescendingly.\n",
|
||||
"readmeFilename": "README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/slide-flow-control/issues"
|
||||
},
|
||||
"_id": "slide@1.1.4",
|
||||
"_from": "slide@latest"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user