Computing with JavaScript Web Workers
ejohn.org
ejohn.org
I started Narwhal (a JavaScript standard library: http://narwhaljs.org) and Jack (a WSGI/Rack-like web server interface: http://jackjs.org) earlier this year with the intention of bringing JavaScript up to par with Ruby, Python, etc.
There are other nice SSJS products, but they're all very monolithic and self-contained (in a bad way). I'm hoping Narwhal will be more modular and open, like we have with most other languages.
While Rhino is currently the most complete Narwhal platform (mostly due to the ease of prototyping in it) We've also started working on V8 (github.com/tlrobinson/narwhal-v8/) and JavaScriptCore (github.com/tlrobinson/narwhal-jsc) support. They're still very incomplete but it's a start.
For example see Flapjax (http://www.flapjax-lang.org)
this clinginess to js strikes me of stockhold syndrome. people are working themselves into a lather as to how awesome and powerful it is, but most of this power is rooted in crappy hacks. namespaces for example. or crockfords currying stuff. very hacky.
js will do. it gets the job done. would i choose to code on the server side with it over python, perl, or haskell? nope
Threads are usually misused. When you add threads and it speeds up your code, you're usually doing something terribly wrong (When #threads>#cores).
IMHO it'd be far nicer just to speed js up and perhaps create some helper functionality to aid in splitting chunks of work up into bite size pieces, and make it more optimal.
It'd be much nicer to just have some yield statement which allows you to say "Hey, it's ok if you process any pending UI events, timers etc etc here". That way you could just have a single main loop with some yields in the right places. It'd create simpler, more maintainable code, and there's no reason it'd be slower or less responsive UI wise than the web worker version.
I can see the examples where web workers can be useful, where you're doing really CPU heavy backgroud work such as image processing etc. But I think people will end up using web workers for far more than that, which will make for some ugly code (IMHO).
As you point out here (http://ejohn.org/blog/postmessage-api-changes/) this will lead to a potential security issue in which you might be responding to messages posted by an external source. Maybe another property could be added, which I'll refer to as messagingDomains. This could be set to a string like 'http://example.com or an array of strings. Each string corresponds to a domain. If this property is set the onmessage would only be called if the origin was from the domain(s) specified in messagingDomains. It's a subtle addition to the API, yes. But it would more clearly establish the existence of a security risk here, because it would probably be propagated better in documentation than a warning to conditionally check event.origin.
For reference, here is how onmessage works right now:
observer.onmessage = function(e) {
if (e.origin == 'http://example.com') {
// I trust this domain, do something
}
}Here is what I think would make sense to clearly establish that security matters here, and as a benefit it would not break backward compatibility:
observer.messagingDomains = ['http://one.example.com, 'http://two.example.com];
observer.onmessage = function(e) {
// By default execute accordingly.
// However, if messagingDomains is set, only execute if the domain is mentioned explicitly
}* All communication is done via strings. This is really a hack which takes advantage of the immutability of strings in JS. Maybe some kind of queueing/message passing system would be better but that is another can of worms. * Loading workers via a separate file is nice for the web, and I get the point that it makes sense for keeping workers out of the global namespace. However, I would have liked to see something function (or even object) based.
All that being said. I think it is a good start and is coming at the concurrency problem from the right angle (i.e. no threads/locking).
Very cool feature though, makes the entry level to distributed processing very low.
get used to "kill -9", you're going to be using it to preempt all this amateur-hour worker code people slap together and foist on you
myobject={
start: function(){ /* do stuff */ }
stop: function(){ /* end worker */ }
postMessage:function(){ /* communicate */ }
onmessage: function(){ /* receiving data*/ }
onerror: function(){ /* handle stuff */ }
}
myworker = new Worker(myobject);
myworker.start();
myworker.postMessage("dostuff");
myworker.stop();
Or something like that...On the other hand, allowing for an easy way to call global functions of the child worker would be really nice.
var worker = new Worker("worker.js");
worker.start();
Child Worker: start = function(){
// Gets called by the parent
};
That would be sexy and surely simplify a lot of logic surrounding message passing.Threads we can fire and forget. Threads we can start "inside" our script and let them work while we do other stuff.
myfunnyfunc = function(){/* do long funny stuff */}
mycallback = function(){/* do something when done */}
mythread = new Thread(myfunnyfunc,mycallback);
Asynchronous like xmlhttprequest, just a way to replace the "settimeout" hack.