WORKERS ======== A background JS worker proposal. interface Window { // ... EndPoint createWorker(in DOMString scriptURI); EndPoint createNamedWorker(in DOMString name, in DOMString scriptURI); } interface WorkerWindow { // also supports EventTarget // has access points for: // - XMLHttpRequest // - async and sync database APIs // - setTimeout, setInterval // - all the methods above for creating workers // - DOMImplementation (gives you a way to create Documents) // - a way to set cookies on the URL for the script // - the navigator object // - some sort of access to the offline cache if it's in one void include(in DOMString url); void log(in DOMString s); // log to console readonly attribute EventListener onjoin; readonly attribute EventListener onunload; readonly attribute DOMString name; readonly attribute ReadonlyLocation location; // URL of the script } When createWorker() is called, run the Create A Worker algorithm with the given script and a null name. When createNamedWorker() is called, then first, the origin is checked for any running workers with that name. If none exist, the Create A Worker algorithm with the given script and name is called. Otherwise, the Join A Worker algorithm is invoked, with the running worker in that origin as the worker to join. The base URL of a worker is its script URL, if it was loaded from a URL, or the URL of the document that created it, otherwise. create*Worker() on a Window resolves relative URIs the same way window.open() does, and on a WorkerWindow from the base URL of the worker itself. create*Worker() when called on a script from another origin must fail with a security exception. The Create A Worker algorithm for a script S and a name N is: 1. Create a new thread with a new WorkerWindow object, and name it N, and load script S in it. 2. Once the script in the worker is ready to run, run it. 3. Simultaneously, run the Join A Worker algorithm with the new worker, and return what that algorithm returns. The Join A Worker algorithm for a worker W: 1. Create an EndPointPair p. 2. Return p.endPoint1. 3. Fire a 'join' event on the WorkerWindow object of the worker, with p.endPoint2 as the endPoint in the message. include(url) will download url (assuming it's from the same origin) and run it as a script. Acceptability is defined inductively by the following rules: If there exists an entangled EndPoint pair with both EndPoints active, with one EndPoint associated with a WorkerWindow and the other EndPoint associated with a Window object in a browsing context, then that WorkerWindow object is acceptable. If there exists an entangled EndPoint pair with both EndPoints active, with one EndPoint associated with a WorkerWindow W and the other EndPoint associated with an acceptable WorkerWindow object, then the WorkerWindow object W is also acceptable. When a WorkerWindow stops being acceptable, the user agent must fire an 'unload' event on the WorkerWindow, and must then close the worker. (User agents may allow running scripts to finish cleanly, or may decide to apply a timeout and eventually kill any running script.) EXAMPLE: In the following example, the core database work is abstracted out from the UI side, and multiple windows open from the same domain can share one worker thread in the background doing the database work. Main page: var core = window.createNamedWorkerFromURL("core", "core.js"); core.onmessage = function (event) { if (event.message == 'welcome') { core.postMessage('get-data'); } else if (event.message == 'data') { var pipe = event.endPoint; pipe.onmessage = function (event) { // receives one message per piece of data addData(event.message); // ... } pipe.postMessage('go'); } else { // unknown message } }; // ... // to send data back core.postMessage('set-data:' + data); core.js: initDatabase(); // ... onjoin = function (event) { var ui = event.endPoint; ui.onmessage = function (event) { if (event.message == 'get-data') { // create a pipe and send one line per data item through the pipe var pipe = window.getNewEndPoints(); pipe.endPoint1.onmessage = function (event) { for (var i = 0; i < data.length; i += 1) // ... pipe.endPoint1.postMessage(data[i]); }; ui.postMessage('data', pipe.endPoint2); } else if (event.message.substr(0,9) == 'set-data:') { setData(event.message.substr(9)); // ... } else { // unknown message } }; ui.postMessage('welcome'); }; onunload = function (event) { closeDatabase(); // ... };