______ ______ ______
______ ______________ _________ __________ /_ ___ /______ __________ /__
_ __ `/__ ___/__ / / /__ __ \_ ___/__ __ \__ / _ __ \_ ___/__ //_/
/ /_/ / _(__ ) _ /_/ / _ / / // /__ _ /_/ /_ / / /_/ // /__ _ ,<
\__,_/ /____/ _\__, / /_/ /_/ \___/ /_.___/ /_/ \____/ \___/ /_/|_|
/____/
==================================================================
A synchronous-style flow control library built on top of harmony generators. This library started its life as asyncblock, which was written on top of Fibers.
Installation
npm install asyncblock-generators
Why should I use asyncblock?
- Write async code in synchronous style without blocking the event loop
- Effortlessly combine serial and parallel operations with minimal boilerplate
- Produce code which is easier to read, reason about, and modify
- Compared to flow control libraries, asyncblock makes it easy to share data between async steps. There's no need to create variables in an outer scope or use "waterfall".
- Simplify error handling practices
- If an error occurs in an async step, automatically call your callback with the error, or throw an Error
- Improve debugging by not losing stack traces across async calls
- Line numbers don't change. What's in the stack trace maps directly to your code (You may lose this with CPS transforms)
- If using a debugger, it's easy to step line-by-line through asyncblock code (compared to async libraries)
Usage differences between this module and asyncblock
- All functions passed to an asyncblock must be generator functions (look like function*(){})
- Any time you are waiting on a value to resolve the "yield" keyword must be used
- There is a new shorthand for waiting on one item:
var x = yield fs.readFile(path, 'utf8', flow.callback());
- When using source transformation, .defer() and .future() calls may only be yielded once. (This is probably fixable, but I haven't looked into it yet)
- asyncblock.getCurrentFiber() is not availabe in this module (this is not commonly used)
Cheat sheet for when yield must be used:
yield flow.wait();
yield flow.get('key');
yield flow.sync(setTimeout(flow.add(), 1000);
yield fs.readFile(path, 'utf8', flow.callback())
yield fs.readFile(path, 'utf8').sync()
var x = fs.readFile(path, 'utf8').defer(); console.log(yield x)
var x = fs.readFile(path, 'utf8').future(); console.log(yield x.result)
This library is unable to detect it if you accidentally forget to include a yield keyword. Please pay close attention to including it when necessary.
Overview
Check out the overview to get an at-a-glance overview of the different ways asyncblock can be used. Please note that the docs are for the fibers version of asyncblock, and the examples will need to be translated to include * and yields for the generator version.
Examples
A few quick examples to show off the functionality of asyncblock:
Sleeping in series
var ab = ; ;
Sleeping in parallel
var ab = ; ;
Trapping results
var ab = ; ;
With source transformation
//asyncblock.enableTransform() must be called before requiring modules using this syntax.//See overview / API for more details var ab = ; if ab return; ;
Returning results and Error Handling
var ab = ; if ab return; var { ; //The callback can be specified as the 2nd arg to asyncblock. It will be called with the value returned from the asyncblock as the 2nd arg. //If an error occurs, the callback will be called with the error as the first argument.});
API
Stack traces
Error handling
See error handling documentation
Formatting results
See formatting results documentation
Parallel task rate limiting
Task timeouts
Concurrency
Both generators, and this module, do not increase concurrency in nodejs. There is still only one thread executing at a time. Generators are like threads which are allowed to pause and resume where they left off without blocking the event loop.
Risks
- Generators are fast, but they're not the fastest. CPU intensive tasks may prefer other solutions (you probably don't want to do CPU intensive work in node anyway...)
Compared to other solutions...
A sample program in pure node, using the async library, and using asyncblock-generators.
Pure node
{ var finishedCount = 0; var fileContents = ; var { iffinishedCount < 2 return; fs; }; fs; fs;}
Using async
var async = ; var fileContents = ; async;
Using asyncblock-generators
var ab = ; ;
Using asyncblock + source transformation
//Requires asyncblock.enableTransform to be called before requiring this modulevar ab = ; if ab return; ;