jspipe
Version:
JS/Pipe - coordinating asynchronous code without callbacks or chained functions
310 lines (199 loc) • 6.16 kB
Markdown
<!-- Start src/jspipe.js -->
# Running concurrent code
### job(fn, args)
Run a generator function `fn` as a concurrent job.
##### Example:
```
var pipe = new JSPipe.Pipe();
JSPipe.job(function* () {
pipe.send(1);
});
JSPipe.job(function* () {
while (true) {
yield JSPipe.timeout(250).get();
pipe.send(2);
}
});
JSPipe.job(function* () {
while (true) {
yield JSPipe.timeout(400).get();
pipe.send(3);
}
});
JSPipe.job(function* () {
var data;
while (data = yield pipe.get()) {
console.log(data);
}
});
```
To communicate and synchronize between jobs, send data through a `Pipe`
using `put` (or `send`) and receive data using `get`.
##### Params:
* **Function** *fn* A generator function to execute as a concurrent job
* **Array** *args* Parameters to pass to `fn`
# Communicating & synchronizing between jobs
### Pipe
A pipe provides a way for two jobs to communicate data and synchronize their execution.
One job can send data into the pipe by calling `yield pipe.put(data)` or `pipe.send(data)`
and another job can receive data by calling `yield pipe.get()`.
Once both a sender job and a receiver job are waiting on the pipe a rendezvous occurs,
transferring the data in the pipe to the receiver and consequently synchronizing the two
waiting jobs.
Once synchronized, the two jobs continue execution.
##### Example:
```
var pipe = new Pipe();
```
### Pipe.close()
Mark the pipe as closed.
### Pipe.put(data)
Call `yield pipe.put(data)` from a job (the sender) to put data in the pipe.
The put method will then try to rendezvous with a receiver job, if any.
If there is no receiver waiting for data, the sender will pause until another
job calls `yield pipe.get()`, which will then trigger a rendezvous.
##### Example
```
job(function* () {
yield pipe.put(42);
});
```
##### Params:
* **AnyType** *data* The data to put into the pipe.
### Pipe.get()
Call `yield pipe.get()` from a job (the receiver) to get data from the pipe.
The get method will then try to rendezvous with a sender job, if any.
If there is no sender waiting for the data it sent to be delivered, the receiver will
pause until another job calls `yield pipe.put(data)`, which will then trigger
a rendezvous.
##### Example:
```
job(function* () {
var data;
while (data = yield pipe.get()) {
console.log(data);
}
});
```
##### Return:
* **AnyType** The data that was received from the pipe.
### Pipe.send(data)
Like `put`, but non-blocking. Unlike `put`, do not call with `yield`.
##### Example:
```
pipe.send(42);
```
##### Params:
* **AnyType** *data* The data to put in the pipe.
---
### EventPipe
An EventPipe is a pipe for delivering event data.
##### Example:
```
var pipe = new EventPipe(document, 'keydown', function(evt) {
pipe.send(evt);
});
```
Normally you should use the `listen` function to create an EventPipe instead.
##### Params:
* **Object** *el* An object, such as an HTMLElement, that exposes an addEventListener method.
* **String** *type* The name of the event, e.g. 'keydown'.
* **Function** *handler* The function that is called when the event fires.
### EventPipe.close()
Removes the event listener and closes the Pipe.
# Making pipes
### timeout(ms)
NOTE: will probably get renamed to `pause`.
Create a pipe that receives a value after a specified time. Use `timeout`
to pause a `job`. Other jobs get a chance to execute this job is paused.
##### Example:
```
job(function* () {
yield timeout(200).get();
console.log('200ms elapsed');
});
```
##### Params:
* **Number** *ms* The time to wait before a value is placed in the pipe
##### Return:
* **Pipe** A pipe
### listen(el, type, preventDefault)
Create a `Pipe` that receives event data.
##### Example:
```
var pipe = listen(document, 'keydown');
var keydownEventData = yield pipe.get();
console.log(keydownEventData);
```
##### Params:
* **Object** *el* The object, such as an HTMLElement, on which to listen for events
* **String** *type* The name of the event, e.g. 'keydown'
* **Boolean** *preventDefault* Whether or not `.preventDefault()` should be called
##### Return:
* **Pipe** A pipe
### lazyseq(count, fn)
Creates a pipe with `count` elements, each produced by executing the function `fn`.
##### Example:
```
var pipe = lazyseq(5, function(i) { return i * 10; });
job(function* () {
var data,
result = [];
while (data = yield pipe.get()) {
result.push(data);
}
console.log(result);
});
```
Prints `[0, 10, 20, 30, 40]` to console.
##### Params:
* **Number** *count* The number of elements that should be produced
* **Function** *fn* The function that produces each element. It is invoked with
### denode(fn, args)
Creates a `Pipe` that will get the data produced by a callback-invoking NodeJS
function.
Useful for converting callback style code into sequential code.
##### Example:
```
job(function* () {
var filedata = yield denode(fs.readFile, 'readme.txt');
console.log(filedata);
});
```
##### Params:
* **Function** *fn* A node function that invokes a callback, e.g. fs.readFile
* **Array** *args* The arguments to supply to `fn`
## Transforming pipes
### unique(pipe)
Takes a pipe and produces a new pipe that only receives sequentially unique
values.
##### Example:
```
var pipe1 = new Pipe(),
pipe2 = unique(pipe1);
pipe1.send(1);
pipe1.send(1);
pipe1.send(3);
pipe1.send(1);
job(function* () {
var data,
result = [];
while (data = yield pipe2.get()) {
result.push(data);
}
console.log(result);
});
```
Prints `[1, 3, 1]` to console.
##### Params:
* **Pipe** *pipe* The pipe from which sequentially unique values must be produced
##### Return:
* **Pipe** A Pipe
### pace(ms, pipe)
Produces a new pipe that gets data from a source pipe at a given pace.
##### Params:
* **Number** *ms* The time to wait before getting the next value from the source pipe
* **Pipe** *pipe* The source pipe
##### Return:
* **Pipe** A pipe
<!-- End src/jspipe.js -->