Tuesday, October 12, 2010

Web Workers as Browser/Server Bridges

David Ascher and I had a discussion last week about server side JavaScript. He mentioned that while server side JavaScript would give some small incremental advantage, there would still be a split between what server devs needs and do and what browser devs need and do. Other people have made a similar observation.

Here is one sketch on what server side JavaScript could bring.

Server-side JavaScript

There are two ways to treat the browser and server workload split . One treats the browser as a dumb client, the other as a smart client.

1) Dumb client

Blogs, news sites, wikis. Content Management Systems (CMS). Serve HTML strings to a browser. There is likely some browser interactivity, but the sites can get by without it via progressive enhancement. The server is responsible for generating the HTML from data mashed together with templates.

This use case is well understood problem space. It is not always executed well, but it has been done many times. Having server side JavaScript will help with some sharing of code/design approaches with the browser, but that is about it. Still, for me it would be nice to have SSJS solutions for these cases.

2) Smart client

Servers as APIs/data stores. The server is doing straight-out business logic, data manipulation. The data sent to the browser is just in JSON, preferably not XML.

Server-side JavaScript is useful here given the expressiveness of the language: closures/anonymous functions for callbacks make using async easier to use, and Node's focus on an event loop is a great fit here, a more natural experience for a browser developer to help out with this area.

Using Servers as Web Workers

This an extension of #2. First, go read up on Web Workers. Short review:

var worker = new WebWorker('http://example.com/some/thing');

//Get messages from the worker
worker.onmessage = onMessageFunction;

//Get errors from the worker
worker.onerror = onErrorFunction;

//Post messages to the worker, only
//JSON-compliant messages back and forth
worker.postMessage({"msg": "hello"});

What would be ideal is that instead of running the web worker in the browser, it would do its work on the server. To bootstrap, a small JS shim could be used that runs in the browser that does the server communication to run the code on the server, and then a Web Worker environment/toolkit/library on the server needs to be created. This node-worker project might be a good place to start for the server code.

The important point: an app developer codes the logic on the server to the Web Worker environment, using postMessage to send out responses, onmessage and onerror to receive responses.

The neat thing about this approach: it can be used for simple request/response actions, or for longer term, comet-style long-lived messaging. It also could allow for actually running or mocking the server endpoint in the browser.

There needs to be some way to manage state. It would be nice to "pause" and "resume" a server-based web worker. Maybe that is just cookies, but it has to be secure to things like CSRF, and still give the user the ability to clear that state like they can clear cookies today.

The other nice thing about this model, it fits in with the event loop that JS developers use today, and it is a tightly constrained environment. No messing about with "requests" and "responses" in the traditional server sense.

There are probably concerns about what it does to a REST approach to API development. I am hoping that it just transforms the REST calls into events routed to web workers, not sure how that will shake out yet.

This is a JavaScript sketch, please read the disclaimers.


Kris Zyp said...

REST isn't a type of call, its an architecture (much different than what you are describing here, since this is defined in terms of opaque calls), so you can't resurrect REST by just saying you are doing "REST" routing. However, there are plenty of apps that don't need REST very badly (don't need to leverage the scaling and layering), and for those, this type of opaque RPC-ish style architecture could be a good fit.

James Burke said...

Kris Zyp: I was thinking I would GET some/resource, it maps to some/resource/get.js that implements a worker API. It would only send out one message via the worker API, just returning the resource, and it would promise not to modify the resource.

POST some/resource would some/resource/post.js where it does the modification on the resource given the data passed to the worker as JSON, then sends a message back.

In other words, the web worker API has an input and output, just like say, the servlet API, and REST servers can be built on top of servlet APIs. I agree it is not enough to just implement web workers, there has to be some design on how the mappings are done, what the expectations are for a GET vs a POST, but seems like it could be done?

I apologize though, I am not keen to the subtleties of REST architectures.