6.7 KiB
streamline.js
streamline.js
is a small tool to simplify asynchronous Javascript programming.
Instead of writing hairy code like:
function lineCount(path, callback) {
fs.readFile(path, "utf8", function(err, data) {
if (err) { callback(err); return; }
callback(null, data.split('\n').length);
});
}
Streamline.js lets you write:
function lineCount(path, _) {
return fs.readFile(path, "utf8", _).split('\n').length;
}
You just have to follow a simple rule:
Replace all callbacks by an underscore and write your code as if all functions were synchronous.
Streamline will transform the code and generate the callbacks for you!
And streamline is not limited to a subset of Javascript.
You can use all the flow control features of Javascript in your asynchronous code: conditionals,
loops, try/catch/finally
blocks, anonymous functions, this
, etc.
Streamline generates more or less the callbacks that you would write yourself. So you get the same level of performance as with hand-written callbacks. Also, the generated code is nicely indented, easy to read, and directly available to debuggers.
Streamline also provides futures, and comes with a small optional library of helper functions (see Goodies section below).
On-line demo
You can test streamline.js
directly with the on-line demo
Installation
The easiest way to install streamline.js
is with NPM:
npm install streamline -g
The -g
option installs it globally.
You can also install it locally, without -g
but then the node-streamline
and coffee-streamline
commands will not be in your default PATH.
Note: if you encounter a permission error when installing on UNIX systems, you should retry with sudo
.
Creating and running streamline modules
To create a module called myModule
, put your streamlined source in a file called myModule_.js
.
Then you have several options:
- You can compile your module with
node-streamline -c
. This will create a file calledmyModule.js
that you can directly run with thenode
command, or require from a normal node program. - You can run the module with
node-streamline myModule_
or require it asrequire('myModule_')
from a program that you launch withnode-streamline
. If you choose this option, themyModule.js
file will not be created. - You can run the module with
node-streamline myModule
or require it asrequire('myModule')
from a program that you launch withnode-streamline
. If you choose this option, you have to create an emptymyModule.js
file to initiate the process. - You can load source and transform it on the fly with the
transform
API.
Option 1 is ideal for production code, as your transformed module will be loaded standalone. The transformation engine will not be loaded.
Option 2 is your best option if you do not want to save the transformed code to disk.
Option 3 is ideal for the development phase if you do not have a build script.
The files will only be recompiled if the source has changed (so you won't get the overhead every time you launch your program).
The transformed source will be available on disk, and will be loaded by the debugger (because you require myModule
, not myModule_
).
Also, this option makes the switch to production really easy: recompile the whole tree and run with node
rather than with node-streamline
.
Option 4 is reserved for advanced scenarios where the code is transformed on the fly.
There is an alternative to running your application with node-streamline
:
you can call require('streamline')
from your main script and then run it with node
.
Modules that are required (directly or indirectly) by your main script will be transformed on demand.
Note: streamline can also transform vanilla Javascript files that don't use CommonJS modules and don't target node.
So you can compile them (option 1) and load them directly in the browser from a <script>
directive.
Examples
The examples/diskUsage
directory contains a simple example that traverses directories to compute disk usage.
You can run as follows:
node-streamline diskUsage_ (will not regenerate diskUsage.js)
node-streamline diskUsage (will regenerate diskUsage.js if necessary)
node diskUsage (assumes that diskUsage.js is there and up-to-date)
Interoperability with standard node.js code
You can call standard node functions from streamline code. For example the fs.readFile
function:
function lineCount(path, _) {
return fs.readFile(path, "utf8", _).split('\n').length;
}
You can also call streamline functions as if they were standard node functions. For example:
lineCount("README.md", function(err, result) {
if (err) return console.error("ERROR: " + err.message);
console.log("README has " + result + " lines.");
});
And you can mix streamline functions, classical callback based code and synchrononous functions in the same file.
Streamline will only transform the functions that have the special _
parameter. The other functions will end up unmodified in the output file (maybe slightly reformatted by the narcissus pretty printer though).
Running in other environments
streamline.js
generates vanilla Javascript code that may be run browser-side too.
You can also transform the code in the browser with the transform
API. See the test/*.js
unit test files for examples.
You can also use streamline.js
with CoffeeScript. For example:
coffee-streamline diskUsage_.coffee
See the Compilers wiki page for details.
Goodies
The functions generated by streamline return a future if you call them without a callback. This gives you an easy way to run several asynchronous operations in parallel and resynchronize later. See the futures wiki page for details.
The following subdirectories contain various modules that have been written with streamline.js:
lib/util
: utilities for array manipulation, semaphores, etc.lib/streams
: pull-mode API for node.js streams.lib/require
: infrastructure to support client-side require.lib/tools
: small tools (doc generator for API.md file).
Resources
The API is documented here.
The wiki discusses advanced topics like exception handling.
For support and discussion, please join the streamline.js Google Group.
License
This work is licensed under the MIT license.