如何将 Web Worker 与 Webextensions 一起使用?
How to use Web Workers with Webextensions?
我正在尝试在我的网络扩展中使用网络工作者来使事情变得更快 运行,但我似乎无法使用 MDN 提供的演示网络工作者示例。这是我的清单:
{
"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);
}
如果有人能告诉我我做错了什么或者我的清单中是否有任何遗漏,那就太好了。
事实证明,由于同源策略,您不能在 webextensions 中使用普通的 web worker。但是,您可以通过将 worker 包装在一个 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 are for, or for my case, event pages。
似乎可以从后台页面创建Worker!虽然最初的问题看起来他们正在尝试使用内容脚本,但该功能似乎不可用。
这是一个在后台页面上生成网络工作者的愚蠢且缺乏想象力的示例:
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 将消息从脚本发送到后台页面,然后再返回。
这可能是一个老问题,但如果有人正在寻找除使用 blob 或后台脚本之外的解决方案,这可能就是它 - 没有警告。
如果您尝试使用当前 manifest.js 加载您的 WebWorker,您将收到错误消息。但是,您可以将 worker.js 文件添加为附加资源,以便您的浏览器可以访问它。您可以通过将 web_accessible_resource 键添加到 manifest.json 来实现。注意:指定为键值的路径将相对于清单文件。
{
"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);
此处导入脚本的路径是相对于工作文件本身的。
就是这样 - 享受扩展中的线程。
我正在尝试在我的网络扩展中使用网络工作者来使事情变得更快 运行,但我似乎无法使用 MDN 提供的演示网络工作者示例。这是我的清单:
{
"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);
}
如果有人能告诉我我做错了什么或者我的清单中是否有任何遗漏,那就太好了。
事实证明,由于同源策略,您不能在 webextensions 中使用普通的 web worker。但是,您可以通过将 worker 包装在一个 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 are for, or for my case, event pages。
似乎可以从后台页面创建Worker!虽然最初的问题看起来他们正在尝试使用内容脚本,但该功能似乎不可用。
这是一个在后台页面上生成网络工作者的愚蠢且缺乏想象力的示例:
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 将消息从脚本发送到后台页面,然后再返回。
这可能是一个老问题,但如果有人正在寻找除使用 blob 或后台脚本之外的解决方案,这可能就是它 - 没有警告。
如果您尝试使用当前 manifest.js 加载您的 WebWorker,您将收到错误消息。但是,您可以将 worker.js 文件添加为附加资源,以便您的浏览器可以访问它。您可以通过将 web_accessible_resource 键添加到 manifest.json 来实现。注意:指定为键值的路径将相对于清单文件。
{
"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);
此处导入脚本的路径是相对于工作文件本身的。
就是这样 - 享受扩展中的线程。