Cispy

Communicating Sequential Processes for JavaScript

Fork me on GitHub
Build status Coverage status

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.

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:

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

License

MIT License