Taming the Asynchronous Beast with CSP in JavaScript
jlongster.com
jlongster.com
> It's safe to say that it's becoming quite popular (and validated) and I think we need to try it out in JavaScript.
To be clear, and he mentions that Clojure has core.async, it's been done in JavaScript (if you will) already via ClojureScript.
David Nolen has done a series of posts on it starting at [1].
[1] -- http://swannodette.github.io/2013/07/12/communicating-sequen...
EDIT: And I should have finished reading the post before posting this. He does mention David Nolen's series of posts on ClojureScript and core.async
var ch = new echan('moduleName');
Where the moduleName would be a module that exports a single function that receives two channels.. in, and out for a request/response pattern. An "easy" level of abstraction here where the request/response is only going to pass what works with JSON.stringify/parse, removing circular references.It could work really well for worker handlers... It only needs to be an abstraction around the csp interfaces, as well as the current implementations for web workers and forked processes in node.js
More advanced scenarios could use 0mq for passing a worker to multiple processes... all of that said, it's just an idea.
I think where this lines up very cleanly is as a means of communication with React and flux.
1. https://justin.harmonize.fm/development/2014/08/05/om-and-fl...
Concurrency does not necessarily mean parallelism (multi-threading). CSP-derived mechanisms provide abstractions for units-of-work to yield control to other units-of-work. Here, a unit of work is a function invocation, but it can be a block, a thread-like object etc. With such primitives it is fairly easy to build cooperative (as opposed to pre-emptive) concurrency mechanisms.
For a mature example, see e.g. http://www.stackless.com/
function one() {
console.log("one");
setTimeout(one, 1000);
}
function two() {
console.log("two");
setTimeout(two, 2000);
}
one();
two();
They are executing concurrently, but never in parallel (since javascript is single threaded).Now, how do you coordinate them if you need to? This is what CSP helps you do.
Maybe you could present the CSP alternative, and a basic example use case?
* edit: I guess a basic example is a sliding-buffer that only keeps, and thus only reacts to, the last mouse event. Is this on the right track?
In vanilla javascript, you have to resort to breaking your code up into callbacks, which looks trivial in a two function example but becomes unwieldy once you add a few layers and do error handling.
With CSP you organize your code around channels according to the code's logic, rather than according to the needs of coordination. This makes things like error handling and reasoning about your logic much simpler.
Buzz words and acronyms are getting out of hand on the web.
If I had to make an analogy channels would be queues while signals would be an observable variable.
JavaScript is great with data but is becoming a monstrosity when it comes to concurrency.
Can we all stop and have a deep look at how other languages deal with concurrency. I have (like many of you) used many different languages and have played with several different concurrency models. The bottom line for me is that multiple threads + concurrency frameworks (i.e. no exposed concurrency primitives) are still the best solution.
I appreciate JavaScript is trying to avoid deadlocking etc. but in modern concurrency frameworks this just isn't an issue.
Seriously we're now contorting ourselves around dogma. Please browser folk, come up with a decent solution to save us all of this.
VOTED DOWN FOR HERESY :-)
var ch = chan();
go(function() { var val; while((val = yield take(ch)) !== csp.CLOSED) { console.log(val); } });
go(function() { yield put(ch, 1); yield take(timeout(1000)); yield put(ch, 2); ch.close(); });
Is clean and easy to understand. That's the point I'm making is that this contorting around a problem. I don't want my code littered with all this annotation just so that it can be synchronous.
Also I'm not picking on the one solution, I just want everyone to take a step back and see if we're really heading in the right direction here.
But yeah, if you're arguing for real threads, that's a different discussion. Even so, you'll have to do similar coordination between threads which will look similar.
Note that I am deliberately referencing that whole set of qualifications: "true threading in the browser in Javascript". Drop any chunk of that and it becomes less insane; for instance, WebWorkers drops "true" and gives a very restricted version of threading. Threading JS in general wouldn't be any harder or easier than threading any other dynamic language in theory (though in general those sorts of languages have a really poor track record, but only in practice, not in theory [1]), but adding "in the browser" is a big problem. Maybe if Servo works properly it will be feasible, but until then it would just be a nightmare.
But I would certainly agree that if you have a choice, such as on the backend server, and you choose Javascript for concurrency, you're making a very poor choice. It just isn't what the language was meant for.
[1]: As near as I can tell, they all tried to retrofit threading onto themselves a very long ways into their development (many years if not decades after birth), and the result- vary from "failure" to "barely functional". However if one set out to create a new language in the dynamic family and made threading a concern from day 1 there's no reason I can see you couldn't succeed. Elixir would be a sort of existence proof. It's the retrofitting that failed moreso than the general idea.
async(()=>{
...
});
It's a bit more terse, and implies that the method will be run asynchronously from the parent.It is the sync on async part I am talking about (see code snippet in sub thread). The layering of synchronous constructs on an asynchronous model which only exists to support the single threaded browser model is getting very convoluted. That's the part I'm talking about.
It is perfectly reasonable and trivial to support a multithreaded model in the browser if the multi-threaded code does not alter shared state. Which obviously is the intention of Web Workers and in there case there state seems to be primarily the DOM, I just feel that this is the direction we and browser developers should be looking into more and where the effort needs to be. And that Web Workers are part of the story not the story.
In my experience concurrency can be kept to a remarkably simple level if either the developer or the language/framework author are willing to follow some simple constraints. In my ideal world:
var x= concurrent(function(x) {
return doSomething(x);
})(1000);
Would execute the function without any closure or access to globals (like the DOM). Now we have no shared state, so we could run this function in a parallel thread. Now add back access to stateless resources like HTTP requests and we're rocking and rolling.Web Workers just seem to be a heavy handed approach to achieving this.
If there is a framework or method available to achieve this and I have missed it out of ignorance please someone correct me and show how this can be done simply. My goal is to have simpler code not to win an argument.
In lieu of a decent forum. I'll drop my thoughts here.
I have felt that the fundamental problem with JavaScript is that it cannot pre-empt. Even with its concurrency of web workers the primary example they give shows the flaw inherent in their solution
http://www.whatwg.org/specs/web-apps/current-work/multipage/...
As a challenge, try and write a version of this worker that the owner page can switch between two number sequence algorithms(prime / Fibonacci for example). The only way you can do this is to rework the program until it's back to being a program beholden to events.
You could solve most of this with a pre-emption mechanism. Allow an additional way to respond to certain inputs by registering an interrupt instead of listening to an event.
function myInterrupt(preEmptedState) {
interruptCounter+=1;
//do something useful here
setExecutionState(preEmptedState); //switch execution context back to pre-empted thread.
}
The parameter to the interrupt function is the execution state of the thread that was pre-empted. This can be restarted at the end of the interrupt, stored for continuation at a later time (enabling blocking), or abandoned (effectively terminating the thread).What this would need is:
An execution state object, possibly an opaque object.
addXXXInterruptHandler(interruptHandler) ;; XXX= Timer/Message/Input/etc.
setExecutionState(newState) ;; this function would not return, it would continue the new state.
createExecutionState(main) ;; generate a new execution state object ready to run the function main
triggerInterrupt(interruptType) ;; Allow a tread to trigger an interrupt upon itself.
If interrupts themselves are simply the running of a new execution state then TriggerInterrupt is just a special case of setInterruptState.
Having this as a core would allow a huge number of higher level constructs that would enable blocking functions, and sane interactions with running processes like web workers.
Yes, you would introduce the possibility of race conditions etc. but only if you actually used the new functionality. If you chose to leave it alone you would be on the old single eventy thready system that we know and hate.
It would also mean you could have someone write var x=0; while(x<10) {} without it killing all scripts.
In terms of my suggestion it is simply that we need a language construct that creates a new scope without access to globals or 'this' and creates a pass by reference (i.e. deep cloned) closure. This allows for zero shared state. Then add back in access to no-shared state globals like HTTP access.
Think web workers on a micro not macro scale.