Cispy is a JavaScript library that implements CSP processes and channels. While it represents another in a long line of JavaScript concurrency solutions (callbacks, promises, FRP, async functions, and so on), it's also an excellent tool for writing fully decoupled code, whether or not concurrency is a need.
More information about Cispy and CSP in general is available in other sections of the site.
- What is CSP? (coming soon)
- API Documentation
- Cispy Examples
Installation
In node.js (or using Browserify, Webpack, etc.):
npm install cispy
In the browser:
Download dist/cispy.js and put it into a directory of your choice.
Usage
In node.js (or with Webpack, etc.):
const cispy = require('cispy');
cispy.go(function*() {
...
});
In the browser:
<script src="js/cispy.js"></script>
<script>
cispy.go(function*() {
...
});
</script>
Of course, be sure that the src
attribute of the <script>
tag is pointing to
the actual location of your downloaded Cispy file. This exposes a global variable named cispy
.
In both of these cases, what you get is a transpiled library that will work fine in an ES5 environment, adding all of the ES2015/2017 features that are required without polluting the global namespace. It is still standard to distribute in ES5.
If you're building your own library, however, you may not want or need to be limited to ES5. If this is the
case, you can change your require
line to this:
const cispy=require('cispy/src/cispy');
This will supply the ES2015 source, which you can use in an ES2015 environment, to do your own transpiling
later, etc. There is no option for an ES2015 browser distribution at this time, because there are still too
many browsers in common use that don't support ES2015/2017 features. If you don't care and want to use ES2015
code in the browser anyway, then make a Webpack project and load Cispy through the require
expression just above.
New in 1.0: Cispy/promise works with async functions
An async function, new in ES2017 but already pretty well supported in browsers, does a very good imitation of
a CSP process. Cispy now includes a separate promise-based library that uses
async
/await
in place of function*
/yield
.
This is not production-ready code. In particular, figuring out how to fake JavaScript timers in the context of async functions is proving difficult, and this is central to testing many parts of the system. So I've temporarily disabled all of the unit tests for this async function-based implementation. Everything seems to work well when I test manually, but until I can verify that over and over, caveat emptor.
This promise-based implementation is available to browsers at
dist/cispy.promise.js
and is included in the distribution for node.js users. The require
statement for this version is
const cispy = require('cispy/promise');
Or, if you prefer using ES2015/2017 directly:
const cispy = require('cispy/src/promise');
Either way, you still get a cispy
object, and it does the same thing as the standard object
except using promises instead of generators. The only difference in the API is that goSafe
and
spawn
do not exist in the promise-based implementation because they aren't necessary when you don't
have processes.
API Documentation
API documentation is available that covers every available function. More documentation about the concepts and how to use CSP in general is planned, though admittedly every time I write something I think of three more things to write about.
Some of the best documentation is probably the unit tests available in the source's test directory.
Examples
There are a few examples (slowly growing) of Cispy at work. Explanations are included along with the code.
Requirements
Cispy requires ES2015 generators.
Browsers
Browser | Version | Notes |
---|---|---|
Chrome | 39.0 | There has been experimental generator support in Chrome since 26.0. |
Firefox | 29.0 |
Generators were actually implemented in version 26.0, but the generator functions themselves would throw an error (instead of returning a result object) when they completed. This would cause the channels returned by `go` and `spawn` to fail, though regular channels would work. Older versions of Firefox did have generator support, but for a generator proposal that did not come to pass. These versions will not work. |
Opera | 26 | |
Internet Explorer | no support | |
Edge | 13 | Experimental support can be enabled in version 12 via "Enable experimental JavaScript features" under about:flags |
Safari | 10 |
Runtimes
Runtime | Version | Notes |
---|---|---|
Node.js | 4.0 |
Support was enabled as of 0.11.6 but required using the --harmony or
--harmony-generators flags.
|
Requirements for Cispy/promise
Cispy/promise requires ES2017 async functions. Well, that's not completely true - it'll work in any environment that supports promises. But the library was designed to work with async functions, so using the promise-based channel functions with plain promises is pretty painful and very much not recommended.
Browsers
Browser | Version | Notes |
---|---|---|
Chrome | 55.0 | |
Firefox | 52.0 | |
Opera | 42 | |
Internet Explorer | no support | |
Edge | 15 | Experimental support can be enabled in version 14, build 14342 or later via about:flags. |
Safari | 10.1 |
Runtimes
Runtime | Version | Notes |
---|---|---|
Node.js | 7.6 |
Support was enabled as of 7.0 but required using the --harmony or
--harmony-async-await flags.
|
Transpilers
Every modern non-supported browser above can have support enabled by transpiling your code into ES5 code. These transpilers all work well.
Transducers
Cispy channels have support for transducers that follow the pseudo-standard that seems to have been established among the maintainers of several JavaScript transducer libraries. All of the following should be compatible with Cispy channels:
- Xduce by Barandis (me)
- transducers-js by cognitect-labs (the same folks that created the transducers used in Clojure)
- transducers.js by jlongster
Each of these libraries is a bit different from the others, though all are excellent. Though they all should work well, I have of course done most of my testing only with my own library.
Important note: These transducer libraries established a protocol and an option to use symbols instead of strings for the protocol property names. Unfortunately, the other libraries seem to have stopped development over a year ago. I intend soon to switch Xduce over to symbols, reasoning that now that ES2017 is out we should probably be ready to use ES2015 stuff. When that happens, the other transducer libraries won't work so well unless they also upgrade to symbols.
Inspiration
Aside from the actual Go and Clojure implementations of CSP, there have been some people whose work has been invaluable in progressing CSP.
Other JS implementations
The second is actually a fork of the first, so there are a lot of similarities. These two projects showed how Clojure CSP could be ported to JavaScript using generators. Cispy is modeled around the techniques used by both of these. Unfortunately they haven't been updated much in the last 1-2 years.
Articles/Blog posts
- Communicating Sequential Processes by swannodette (in Clojure)
- Taming the Asynchronous Beast by jlongster
License
MIT License