|
|
| (13 intermediate revisions by 3 users not shown) |
| Line 1: |
Line 1: |
| == DOM Worker Threads API Proposal == | | == Web Worker API Proposal == |
|
| |
|
| == Abstract == | | == API Proposal == |
| | |
| This is an API '''proposal''' for DOM Worker Threads.
| |
| | |
| At this time this document is not complete and is not yet ready for general consideration or debate. It's just getting started!
| |
| | |
| Look for a post to mozilla.dev.platform when this proposal is ready to be discussed.
| |
| | |
| == Introduction ==
| |
| | |
| === Use Cases ===
| |
| | |
| === Terminology ===
| |
| | |
| A '''worker''' is an execution context for JavaScript that runs off of the main UI thread. The global scope for a worker is almost empty - familiar objects such as <code>window</code> and <code>document</code> are not available, nor is the Mozilla-specific <code>Components</code> object.
| |
| | |
| A '''worker pool''' is a collection of related workers. Workers within a pool can communicate with each other freely, but workers cannot communicate with workers from another pool.
| |
| | |
| == Conformance ==
| |
| | |
| == Dependencies ==
| |
| | |
| == Specification Proposal ==
| |
|
| |
|
| <blockquote> | | <blockquote> |
| <code> | | <code> |
| <pre> | | <pre> |
| #include "nsISupports.idl"
| |
|
| |
|
| interface nsIDOMWorkerThread; | | [NoInterfaceObject] interface WorkerFactory { |
| interface nsIScriptError;
| | Worker createWorker(in DOMString scriptURL); |
| | }; |
|
| |
|
| [scriptable, function, uuid(e50ca05d-1381-4abb-a021-02eb720cfc38)]
| | interface Worker { |
| interface nsIDOMWorkerMessageListener : nsISupports | | void postMessage(in DOMString aMessage); |
| { | |
| /**
| |
| * An nsIDOMWorkerThread receives the onMessage callback when another
| |
| * worker posts a message to it.
| |
| *
| |
| * @param aMessage (in DOMString)
| |
| * The message sent from another worker.
| |
| * @param aSource (in nsIDOMWorkerThread)
| |
| * The worker that sent the message. Useful for a quick response.
| |
| */
| |
| void onMessage(in DOMString aMessage, | |
| in nsIDOMWorkerThread aSource);
| |
| };
| |
|
| |
|
| [scriptable, function, uuid(9df8422e-25dd-43f4-b9b9-709f9e074647)]
| | // event handler attributes |
| interface nsIDOMWorkerErrorListener : nsISupports
| | attribute EventListener onmessage; |
| {
| | attribute EventListener onerror; |
| /** | | attribute EventListener onload; |
| * An nsIDOMWorkerPool receives the onError callback when one of its child
| | attribute EventListener onunload; |
| * workers has a parse error or an unhandled exception.
| |
| *
| |
| * @param aMessage (in nsIScriptError)
| |
| * Details about the error that occurred. See nsIScriptError.
| |
| * @param aSource (in nsIDOMWorkerThread)
| |
| * The worker that sent the message. Depending on the specific error in
| |
| * question it may not be possible to use this object (in the case of a
| |
| * parse error, for instance, aSource will be unusable).
| |
| */
| |
| void onError(in nsIScriptError aError,
| |
| in nsIDOMWorkerThread aSource);
| |
| }; | | }; |
|
| |
|
| [scriptable, uuid(6f19f3ff-2aaa-4504-9b71-dca3c191efed)]
| |
| interface nsIDOMWorkerThread : nsISupports
| |
| {
| |
| /**
| |
| * Sends a message to the worker.
| |
| *
| |
| * @param aMessage (in DOMString)
| |
| * The message to send. This may be a string or an object that can be
| |
| * serialized via JSON (see http://developer.mozilla.org/en/docs/JSON).
| |
| */
| |
| void postMessage(in DOMString aMessage);
| |
| };
| |
|
| |
|
| [scriptable, uuid(45312e93-8a3e-4493-9bd9-272a6c23a16c)] | | [NoInterfaceObject] interface WorkerGlobalScope |
| interface nsIDOMWorkerPool : nsIDOMWorkerThread | |
| { | | { |
| /** | | readonly attribute WorkerGlobalScope self; |
| * The nsIDOMWorkerErrorListener which handles errors in child threads.
| | readonly attribute WorkerLocation location; |
| *
| | readonly attribute boolean closing; |
| * Developers should set this attribute to a proper object before calling
| | void close(); |
| * createWorker in order to catch parse errors as well as runtime exceptions.
| |
| */
| |
| attribute nsIDOMWorkerErrorListener errorListener; | |
|
| |
|
| /** | | // event handler attributes |
| * Create a new worker object by evaluating the given script.
| | attribute EventListener onunload; |
| *
| |
| * @param aSourceScript (in DOMString)
| |
| * The script to compile. See below for details on the scope in which
| |
| * the script will run.
| |
| */
| |
| nsIDOMWorkerThread createWorker(in DOMString aScriptText);
| |
|
| |
|
| /** | | // WorkerUtils |
| * Create a new worker object by evaluating the given script file.
| | void importScripts([Variadic] in DOMString urls); |
| *
| | readonly attribute Storage localStorage; |
| * @param aSourceScript (in nsIURI)
| | Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize); |
| * The script file to compile. See below for details on the scope in
| | void showNotification(in DOMString title, in DOMString subtitle, in DOMString description); |
| * which the script will run. See nsIURI.
| | void showNotification(in DOMString title, in DOMString subtitle, in DOMString description, in VoidCallback onclick); |
| */
| |
| nsIDOMWorkerThread createWorkerFromURI(in DOMString aScriptURI); | |
| }; | | }; |
|
| |
|
| [scriptable, function, uuid(fc8c2d9c-7b0e-467e-91f8-4715497d8ac6)] | | [NoInterfaceObject] interface WorkerLocation { |
| interface nsIDOMWorkerHttpRequestCallback : nsISupports
| | readonly attribute DOMString href; |
| {
| | readonly attribute DOMString protocol; |
| void onChange(); | | readonly attribute DOMString host; |
| | readonly attribute DOMString hostname; |
| | readonly attribute DOMString port; |
| | readonly attribute DOMString pathname; |
| | readonly attribute DOMString search; |
| | readonly attribute DOMString hash; |
| }; | | }; |
|
| |
|
| [scriptable, uuid(b66e5bf1-3269-4e33-ab32-4786fec42377)]
| | </pre> |
| interface nsIDOMWorkerHttpRequest : nsISupports
| | </code> |
| {
| | </blockquote> |
| /**
| |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| readonly attribute AString responseText;
| |
|
| |
|
| /**
| | === Sample usage === |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| readonly attribute unsigned long status;
| |
|
| |
|
| /**
| | This is a '''very''' suboptimal way of calculating a number in the Fibonacci sequence. |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| readonly attribute AUTF8String statusText;
| |
|
| |
|
| /**
| | Main page: |
| * See nsIXMLHttpRequest.idl
| | <blockquote> |
| */
| | <code> |
| void abort(); | | <pre> |
| | worker = createWorker("f.js"); |
| | worker.onmessage = function(e) { |
| | alert("The 100th Fibonacci number is " + e.data); |
| | } |
| | worker.postMessage(100); |
| | </pre> |
| | </code> |
| | </blockquote> |
|
| |
|
| /**
| | f.js: |
| * See nsIXMLHttpRequest.idl
| | <blockquote> |
| */
| | <code> |
| string getAllResponseHeaders();
| | <pre> |
| | parent.onmessage = function(e) { |
| | if (e.data <= 1) |
| | postMessage(e.data); |
|
| |
|
| /** | | w1 = createWorker("f.js"); |
| * See nsIXMLHttpRequest.idl
| | w1.onmessage = handler; |
| */
| | w1.postMessage(e.data - 1); |
| ACString getResponseHeader(in AUTF8String header); | | |
| | w2 = createWorker("f.js"); |
| | w2.onmessage = handler; |
| | w2.postMessage(e.data - 2); |
| | } |
|
| |
|
| /**
| | c = 0; |
| * See nsIXMLHttpRequest.idl
| | sum = 0; |
| */
| |
| void open(in AUTF8String method, in AUTF8String url);
| |
|
| |
|
| /** | | function handler(e) { |
| * See nsIXMLHttpRequest.idl
| | sum += parseInt(e.data); |
| */
| | if (++c == 2) { |
| void send(in nsIVariant body);
| | postMessage(sum); |
| | } |
| | } |
| | </pre> |
| | </code> |
| | </blockquote> |
|
| |
|
| /**
| | == References == |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| void sendAsBinary(in DOMString body);
| |
|
| |
|
| /**
| | The only thing I've seen so far is the [http://code.google.com/apis/gears/api_workerpool.html Google Gears WorkerPool API]. We would certainly like to provide a API that would make migrating Gears code trivial. |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| void setRequestHeader(in AUTF8String header, in AUTF8String value);
| |
|
| |
|
| /**
| | == API Proposal For Shared Workers == |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| readonly attribute long readyState;
| |
|
| |
|
| /**
| | If we want to support shared workers in the initial release of this spec, here are two proposals that will work with the above initial API. |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| void overrideMimeType(in AUTF8String mimetype);
| |
|
| |
|
| /**
| | === Proposal 1 === |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| attribute nsIDOMWorkerHttpRequestCallback onload;
| |
|
| |
|
| /**
| | <blockquote> |
| * See nsIXMLHttpRequest.idl
| | <code> |
| */
| | <pre> |
| attribute nsIDOMWorkerHttpRequestCallback onerror;
| |
|
| |
|
| /** | | [NoInterfaceObject] interface WorkerFactory { |
| * See nsIXMLHttpRequest.idl
| | ... |
| */
| | Worker createSharedWorker(in DOMString name, in DOMString scriptURL); |
| attribute nsIDOMWorkerHttpRequestCallback onprogress;
| |
| | |
| /**
| |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| attribute nsIDOMWorkerHttpRequestCallback onuploadprogress;
| |
| | |
| /**
| |
| * See nsIXMLHttpRequest.idl
| |
| */
| |
| attribute nsIDOMWorkerHttpRequestCallback onreadystatechange; | |
| }; | | }; |
|
| |
|
| interface nsIDOMWorkerGlobalScope | | [NoInterfaceObject] interface WorkerParent { |
| { | | void postMessage(in DOMString aMessage); |
| /**
| | attribute EventListener onmessage; |
| * The worker object that created this scope.
| |
| */
| |
| readonly attribute nsIDOMWorkerThread thisThread;
| |
| | |
| /**
| |
| * Sends a message to the pool that created the worker.
| |
| *
| |
| * @param aMessage (in DOMString)
| |
| * The message to send. This may be a string or an object that can be
| |
| * serialized via JSON (see http://developer.mozilla.org/en/docs/JSON).
| |
| */
| |
| void postMessageToPool(in DOMString aMessage); | |
| | |
| /**
| |
| * The nsIDOMWorkerMessageListener which handles messages for this worker.
| |
| *
| |
| * Developers should set this attribute to a proper object before another
| |
| * worker begins sending messages to ensure that all messages are received.
| |
| */
| |
| attribute nsIDOMWorkerMessageListener messageListener; | |
| | |
| /**
| |
| * Loads the script indicated from the given URI.
| |
| *
| |
| * This function will block until the script file has loaded and has been
| |
| * executed.
| |
| *
| |
| * @param aURIString
| |
| * The URI to load.
| |
| *
| |
| * @throws Will throw an error if the URI cannot be loaded or executed.
| |
| */
| |
| void loadScript(in DOMString aURIString);
| |
| | |
| /**
| |
| * Creates a new HttpRequest object.
| |
| *
| |
| * Use: 'var req = new HttpRequest();'
| |
| */
| |
| /* nsIDOMWorkerHttpRequest HttpRequest(); */
| |
| | |
| /**
| |
| * See nsIDOMJSWindow.idl
| |
| */
| |
| void dump(in DOMString str);
| |
| | |
| /**
| |
| * See nsIDOMJSWindow.idl
| |
| */
| |
| long setTimeout(/* in JSObject aFunctionOrString, */
| |
| /* in JSObject aMilisecondDelay, */
| |
| /* [optional] in aArgsToFunctionOrString */);
| |
| | |
| /**
| |
| * See nsIDOMJSWindow.idl
| |
| */
| |
| long setInterval(/* in JSObject aFunctionOrString, */
| |
| /* in JSObject aMilisecondDelay, */
| |
| /* [optional] in aArgsToFunctionOrString */);
| |
| | |
| /**
| |
| * See nsIDOMJSWindow.idl
| |
| */
| |
| void clearTimeout(/* in JSObject aTimeoutId */);
| |
| | |
| /**
| |
| * See nsIDOMJSWindow.idl
| |
| */
| |
| void clearInterval(/* in JSObject aIntervalId */);
| |
| }; | | }; |
|
| |
|
| Line 283: |
Line 130: |
| </blockquote> | | </blockquote> |
|
| |
|
| === The worker pool's scope ===
| | <code>createSharedWorker</code> creates a new <code>Worker</code> object that interacts with the same <code>WorkerGlobalScope</code> as any previously existing <code>Worker</code>s. |
|
| |
|
| The scope for the worker pool is the standard DOM scope. All DOM objects such as <code>window</code> and <code>document</code> are available, as well as functions such as <code>alert()</code> and <code>dump()</code>.
| | When a shared <code>Worker</code> receives a message it can send data back to the sender using the <code>Event.source</code> property which is a <code>WorkerParent</code>. |
|
| |
|
| === The worker's scope ===
| | Using <code>WorkerGlobalScope.postMessage</code> and <code>WorkerGlobalScope.onmessage</code> results in a message being sent to the first context that opened the shared worker (or nothing if that context is dead). |
|
| |
|
| The worker's scope is far more limited. See <code>nsIDOMWorkerGlobalScope</code> above for details. | | Downsides with this proposal: |
| | * There is no way to communicate back unless first communicated to. |
| | * The first one to instantiate a shared worker get special treatment. |
|
| |
|
| === Sample usage === | | === Proposal 2 === |
|
| |
|
| <blockquote> | | <blockquote> |
| <code> | | <code> |
| <pre> | | <pre> |
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
| |
| <html>
| |
| <title>Test threads</title>
| |
| <body>
| |
| <script language="javascript">
| |
| var scriptToRun = 'function messageListener(message, source) { ' +
| |
| ' dump("Worker: " + message + "\\n"); ' +
| |
| '} ' +
| |
| 'for (var i = 0; i < 10000000; i++) { ' +
| |
| ' /* do something */ ' +
| |
| '} '+
| |
| 'sendMessageToPool("Done!"); ';
| |
|
| |
|
| var wp = navigator.newWorkerPool();
| | [NoInterfaceObject] interface WorkerFactory { |
| wp.messageListener = function(message, source) {
| | ... |
| dump("Pool: " + message + "\n");
| | MessagePort connectToSharedWorker(in DOMString name, in DOMString scriptURL); |
| };
| | }; |
| wp.errorListener = function(error, source) {
| |
| dump("Pool: error = '" + error + "'\n");
| |
| }
| |
|
| |
|
| var threads = []
| | [NoInterfaceObject] interface WorkerGlobalScope { |
| for (var i = 0; i < 10; i++) {
| | ... |
| var thread = wp.createWorker(scriptToRun);
| | attribute EventListener onconnect; |
| thread.postMessage("hello");
| | }; |
| threads.push(thread);
| |
| }
| |
| | |
| </script>
| |
| </body>
| |
| </html>
| |
|
| |
|
| </pre> | | </pre> |
| Line 332: |
Line 160: |
| </blockquote> | | </blockquote> |
|
| |
|
| == Not In This Specification ==
| | <code>connectToSharedWorker</code> creates a two new <code>MessagePort</code> which are entangled with each other. One of the two ports is returned, and the other is sent to the <code>Worker</code> with the given name. If such a <code>Worker</code> does not yet exist, one is created. |
| | |
| == References ==
| |
|
| |
|
| The only thing I've seen so far is the [http://code.google.com/apis/gears/api_workerpool.html Google Gears WorkerPool API]. We would certainly like to provide a compatibility API that would make migrating Gears code trivial. | | The <code>Worker</code> receives the other <code>MessagePort</code> through an <code>onconnect</code> <code>Event</code> fired on the <code>WorkerGlobalScope</code> object. |
|
| |
|
| == Acknowledgements ==
| | * There is no way to get a reference to the shared <code>Worker</code> object itself. |
| | * Communication for shared workers is different from communication for non-shared ones. |