如何使用Webextensions的Web Workers?

时间:2017-12-04 20:40:35

标签: javascript web-worker firefox-webextensions

我正在尝试在我的webextension中使用Web worker来使事情运行得更快,但我似乎无法获得MDN提供的演示webworker示例。这是我的表现:

{
  "manifest_version": 2,
  "name": "test",
  "version": "1.0.0",

  "content_scripts": [
    {
      "matches": [
        "http://*/*",
        "https://*/*"
      ],
      "js": [
        "sharedTest.js"
      ]
    }
  ]
}

这是sharedTest.js:

console.log("js loaded");
if (window.Worker) { // Check if Browser supports the Worker api.
    // Requires script name as input
    var myWorker = new Worker(browser.runtime.getURL('testWorker.js'));
    myWorker.onmessage = function(e) {
        console.log('Message received from worker');
    console.log(e.data);
    };
  myWorker.postMessage([42, 23]); // Sending message as an array to the worker
  console.log('Message posted to worker');
}

这是testWorker.js:

onmessage = function(e) {
  console.log('Message received from main script');
  var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
  console.log('Posting message back to main script');
  postMessage(workerResult);
}

如果有人能告诉我我做错了什么,或者我的清单中有什么遗漏,那就太好了。

3 个答案:

答案 0 :(得分:2)

事实证明,由于同源策略,您无法在webextensions中使用普通的Web工作者。但是,您可以通过将工作程序包装在一个blob中来解决这个问题:

var blob = new Blob([
    `onmessage = function(e) {
       console.log('Message received from main script');
       var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
       console.log('Posting message back to main script');
       postMessage(workerResult);
     }`]);

// Obtain a blob URL reference to our worker 'file'.
var blobURL = window.URL.createObjectURL(blob);

var worker = new Worker(blobURL);
worker.onmessage = function(e) {
    console.log('Message received from worker');
    console.log(e.data);
};
  worker.postMessage([42, 23]); // Sending message as an array to the worker
  console.log('Message posted to worker');

这将有效。上面的示例基于this article,并且在webextensions中有效(理论上除了Internet Explorer之外的所有内容)。但是,该blob worker不再与扩展的其余部分位于同一源,因此由于同源策略,全局importScripts()将无法导入扩展中的任何文件。这意味着您必须在Blob中包含所有必要的方法和逻辑,这不太理想。

或者,我意识到这是background scripts的用途,或者我的情况event pages

答案 1 :(得分:0)

似乎可以从后台页面创建Workers!当最初的问题看起来像他们试图使用内容脚本时,该功能似乎不可用。

这是一个在后台页面上生成网络工作者的愚蠢且难以想象的示例:

manifest.json

{
  "manifest_version": 2,

  "name": "",
  "description": "",
  "version": "0.0.1",

  "background": { "page": "background.html" }
}

background.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <script src="background.js"></script>
  </head>
</html>

background.js

if(window.Worker)
{
    const myWorker = new Worker(browser.runtime.getURL('worker.js'));

    myWorker.onmessage = function(msg) {
        console.log("Main Script: Message received", msg.data);
    }

    let i = 0;
    setInterval(() => {myWorker.postMessage({num: i++});}, 500);
}
else
{
    console.log("Worker's not supported :(")
}

worker.js

onmessage = function(msg) 
{
    postMessage({timestamp: Date.now(), passedData: msg.data});
}

如果您需要使用内容脚本,则可以使用ports将消息从脚本发送到后台页面,然后再次发送。

答案 2 :(得分:0)

这可能是一个古老的问题,但是如果有人正在寻找除使用Blob或后台脚本之外的解决方案,那就可能是-没有警告。

如果尝试使用当前的manifest.js加载WebWorker,则会收到错误消息。但是,您可以将worker.js文件添加为附加资源,以便浏览器可以访问它。您可以通过在manifest.json中添加web_accessible_resource键来实现。注意:指定为键值的路径将相对于清单文件。

{
  "manifest_version": 2,
  "name": "MyExtension",
  "version": "1.0",

  "content_scripts": [
    {
      "all_frames": true,
      "matches": [ "<all_urls>" ],
      "js": [ "js/content.js", "js/import.js" ],
      "run_at": "document_end",
      "css": ["css/style.css"]
    }
  ],
  "web_accessible_resources": [ "js/worker.js", "pictures/cat.svg" ]
}

然后您可以从content.js获取工作程序的运行时URL,以创建工作程序:

const worker = new Worker(browser.runtime.getURL('js/worker.js'));
worker.onmessage = (e) => {window.console.log(e);

要将脚本导入到工作人员,首先需要在清单(相对于清单的路径)中将其指定为内容脚本。然后,您可以在工作人员中将其导入为:

self.importScripts('import.js');
self.onmessage = (e) => importStuff.doWork(e); 

此处导入脚本的路径是相对于工作文件本身的。

就这样-享受扩展程序中的线程。