X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.maps.server%2Fnode%2Fnode-v4.8.0-win-x64%2Fnode_modules%2Fnpm%2Fnode_modules%2Fslide%2FREADME.md;fp=org.simantics.maps.server%2Fnode%2Fnode-v4.8.0-win-x64%2Fnode_modules%2Fnpm%2Fnode_modules%2Fslide%2FREADME.md;h=59ad738bca2e5004daedeef44fd97a55bf674171;hb=2529be6d456deeb07c128603ce4971f1dc29b695;hp=0000000000000000000000000000000000000000;hpb=2636fc31c16c23711cf2b06a4ae8537bba9c1d35;p=simantics%2Fdistrict.git diff --git a/org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/slide/README.md b/org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/slide/README.md new file mode 100644 index 00000000..59ad738b --- /dev/null +++ b/org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/slide/README.md @@ -0,0 +1,143 @@ +# 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.