Bug 1140172 - Use a single reader worker instead of spawning infinite workers. r=bnicholson f=Yoric
authorMargaret Leibovic <margaret.leibovic@gmail.com>
Thu, 05 Mar 2015 17:31:05 -0800
changeset 249027 61faee68488e8a051d5f55a53039a05c0b44b4ce
parent 249026 67afb0cebf9a97ce909530f1617eb272075625d5
child 249028 d164b59f3b94216283f6fa608258c5bc77f24fe6
push id966
push usermleibovic@mozilla.com
push dateTue, 10 Mar 2015 01:36:33 +0000
reviewersbnicholson
bugs1140172
milestone39.0a1
Bug 1140172 - Use a single reader worker instead of spawning infinite workers. r=bnicholson f=Yoric
toolkit/components/reader/JSDOMParser.js
toolkit/components/reader/Readability.js
toolkit/components/reader/ReaderMode.jsm
toolkit/components/reader/ReaderWorker.js
toolkit/components/reader/ReaderWorker.jsm
toolkit/components/reader/content/JSDOMParser.js
toolkit/components/reader/content/Readability.js
toolkit/components/reader/content/readerWorker.js
toolkit/components/reader/jar.mn
toolkit/components/reader/moz.build
rename from toolkit/components/reader/content/JSDOMParser.js
rename to toolkit/components/reader/JSDOMParser.js
rename from toolkit/components/reader/content/Readability.js
rename to toolkit/components/reader/Readability.js
--- a/toolkit/components/reader/ReaderMode.jsm
+++ b/toolkit/components/reader/ReaderMode.jsm
@@ -10,16 +10,17 @@ const { classes: Cc, interfaces: Ci, uti
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 Cu.importGlobalProperties(["XMLHttpRequest"]);
 
 XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils", "resource://services-common/utils.js");
 XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ReaderWorker", "resource://gre/modules/reader/ReaderWorker.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm");
 
 this.ReaderMode = {
   // Version of the cache schema.
   CACHE_VERSION: 1,
 
   DEBUG: 0,
 
@@ -194,67 +195,51 @@ this.ReaderMode = {
    * Attempts to parse a document into an article. Heavy lifting happens
    * in readerWorker.js.
    *
    * @param uri The article URI.
    * @param doc The document to parse.
    * @return {Promise}
    * @resolves JS object representing the article, or null if no article is found.
    */
-  _readerParse: function (uri, doc) {
-    return new Promise((resolve, reject) => {
-      let numTags = doc.getElementsByTagName("*").length;
-      if (numTags > this.MAX_ELEMS_TO_PARSE) {
-        this.log("Aborting parse for " + uri.spec + "; " + numTags + " elements found");
-        resolve(null);
-        return;
-      }
+  _readerParse: Task.async(function* (uri, doc) {
+    let numTags = doc.getElementsByTagName("*").length;
+    if (numTags > this.MAX_ELEMS_TO_PARSE) {
+      this.log("Aborting parse for " + uri.spec + "; " + numTags + " elements found");
+      return null;
+    }
 
-      let worker = new ChromeWorker("chrome://global/content/reader/readerWorker.js");
-      worker.onmessage = evt => {
-        let article = evt.data;
-
-        if (!article) {
-          this.log("Worker did not return an article");
-          resolve(null);
-          return;
-        }
-
-        // Readability returns a URI object, but we only care about the URL.
-        article.url = article.uri.spec;
-        delete article.uri;
+    let uriParam = {
+      spec: uri.spec,
+      host: uri.host,
+      prePath: uri.prePath,
+      scheme: uri.scheme,
+      pathBase: Services.io.newURI(".", null, uri).spec
+    };
 
-        let flags = Ci.nsIDocumentEncoder.OutputSelectionOnly | Ci.nsIDocumentEncoder.OutputAbsoluteLinks;
-        article.title = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils)
-                                                        .convertToPlainText(article.title, flags, 0);
-        resolve(article);
-      };
+    let serializer = Cc["@mozilla.org/xmlextras/xmlserializer;1"].
+                     createInstance(Ci.nsIDOMSerializer);
+    let serializedDoc = yield Promise.resolve(serializer.serializeToString(doc));
 
-      worker.onerror = evt => {
-        reject("Error in worker: " + evt.message);
-      };
+    let article = yield ReaderWorker.post("parseDocument", [uriParam, serializedDoc]);
 
-      try {
-        let serializer = Cc["@mozilla.org/xmlextras/xmlserializer;1"].
-                         createInstance(Ci.nsIDOMSerializer);
-        worker.postMessage({
-          uri: {
-            spec: uri.spec,
-            host: uri.host,
-            prePath: uri.prePath,
-            scheme: uri.scheme,
-            pathBase: Services.io.newURI(".", null, uri).spec
-          },
-          doc: serializer.serializeToString(doc)
-        });
-      } catch (e) {
-        reject("Reader: could not build Readability arguments: " + e);
-      }
-    });
-  },
+    if (!article) {
+      this.log("Worker did not return an article");
+      return null;
+    }
+
+    // Readability returns a URI object, but we only care about the URL.
+    article.url = article.uri.spec;
+    delete article.uri;
+
+    let flags = Ci.nsIDocumentEncoder.OutputSelectionOnly | Ci.nsIDocumentEncoder.OutputAbsoluteLinks;
+    article.title = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils)
+                                                    .convertToPlainText(article.title, flags, 0);
+    return article;
+  }),
 
   get _cryptoHash() {
     delete this._cryptoHash;
     return this._cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
   },
 
   get _unicodeConverter() {
     delete this._unicodeConverter;
rename from toolkit/components/reader/content/readerWorker.js
rename to toolkit/components/reader/ReaderWorker.js
--- a/toolkit/components/reader/content/readerWorker.js
+++ b/toolkit/components/reader/ReaderWorker.js
@@ -1,12 +1,46 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-importScripts("JSDOMParser.js", "Readability.js");
+"use strict";
+
+/**
+ * A worker dedicated to handle parsing documents for reader view.
+ */
+
+importScripts("resource://gre/modules/workers/require.js",
+	          "resource://gre/modules/reader/JSDOMParser.js",
+	          "resource://gre/modules/reader/Readability.js");
+
+let PromiseWorker = require("resource://gre/modules/workers/PromiseWorker.js");
 
-self.onmessage = function (msg) {
-  let uri = msg.data.uri;
-  let doc = new JSDOMParser().parse(msg.data.doc);
-  let article = new Readability(uri, doc).parse();
-  postMessage(article);
+let worker = new PromiseWorker.AbstractWorker();
+worker.dispatch = function(method, args = []) {
+  return Agent[method](...args);
+};
+worker.postMessage = function(result, ...transfers) {
+  self.postMessage(result, ...transfers);
+};
+worker.close = function() {
+  self.close();
+};
+worker.log = function(...args) {
+  dump("ReaderWorker: " + args.join(" ") + "\n");
 };
+
+self.addEventListener("message", msg => worker.handleMessage(msg));
+
+let Agent = {
+  /**
+   * Parses structured article data from a document.
+   *
+   * @param {object} uri URI data for the document.
+   * @param {string} serializedDoc The serialized document.
+   *
+   * @return {object} Article object returned from Readability.
+   */
+  parseDocument: function (uri, serializedDoc) {
+    let doc = new JSDOMParser().parse(serializedDoc);
+    return new Readability(uri, doc).parse();
+  },
+};
new file mode 100644
--- /dev/null
+++ b/toolkit/components/reader/ReaderWorker.jsm
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/**
+ * Interface to a dedicated thread handling readability parsing.
+ */
+
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/PromiseWorker.jsm", this);
+
+this.EXPORTED_SYMBOLS = ["ReaderWorker"];
+
+this.ReaderWorker = new BasePromiseWorker("resource://gre/modules/reader/ReaderWorker.js");
--- a/toolkit/components/reader/jar.mn
+++ b/toolkit/components/reader/jar.mn
@@ -1,10 +1,7 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit.jar:
   content/global/reader/aboutReader.html             (content/aboutReader.html)
   content/global/reader/aboutReader.js               (content/aboutReader.js)
-  content/global/reader/Readability.js               (content/Readability.js)
-  content/global/reader/JSDOMParser.js               (content/JSDOMParser.js)
-  content/global/reader/readerWorker.js              (content/readerWorker.js)
--- a/toolkit/components/reader/moz.build
+++ b/toolkit/components/reader/moz.build
@@ -5,8 +5,15 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 JAR_MANIFESTS += ['jar.mn']
 
 EXTRA_JS_MODULES += [
   'AboutReader.jsm',
   'ReaderMode.jsm'
 ]
+
+EXTRA_JS_MODULES.reader = [
+  'JSDOMParser.js',
+  'Readability.js',
+  'ReaderWorker.js',
+  'ReaderWorker.jsm'
+]