如何使用字符串创建Web worker(通过POST请求提供)?
我能想到的一种方法,但我不确定如何实现它,是通过从服务器响应创建数据URI,并将其传递给Worker构造函数,但我听说有些浏览器不知道不允许这样,因为原产地政策相同。
MDN states the uncertainty about the origin policy around data URI's:
注意:作为Worker构造函数的参数传递的URI必须遵循同源策略。目前,浏览器供应商对数据URI是否来源不一致存在分歧; Gecko 10.0(Firefox 10.0 / Thunderbird 10.0)及更高版本确实允许数据URI作为工作人员的有效脚本。其他浏览器可能不同意。
这里还有帖子discussing it on the whatwg。
答案 0 :(得分:128)
摘要
blob:
适用于Chrome 8 +,Firefox 6 +,Safari 6.0 +,Opera 15 +data:application/javascript
适用于Opera 10.60 - 12eval
否则(IE 10 +)
URL.createObjectURL(<Blob blob>)
可用于从字符串创建Web worker。可以使用BlobBuilder
API 已弃用或Blob
constructor创建blob。
演示:http://jsfiddle.net/uqcFM/49/
// URL.createObjectURL
window.URL = window.URL || window.webkitURL;
// "Server response", used in all examples
var response = "self.onmessage=function(e){postMessage('Worker: '+e.data);}";
var blob;
try {
blob = new Blob([response], {type: 'application/javascript'});
} catch (e) { // Backwards-compatibility
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
blob = new BlobBuilder();
blob.append(response);
blob = blob.getBlob();
}
var worker = new Worker(URL.createObjectURL(blob));
// Test, used in all examples:
worker.onmessage = function(e) {
alert('Response: ' + e.data);
};
worker.postMessage('Test');
以下浏览器支持Web worker source :
此方法的支持基于Blob
API和URL.createObjectUrl
方法的支持。 Blob
compatibility:
WebKitBlobBuilder
),20 +(Blob
构造函数)MozBlobBuilder
),13 +(Blob
构造函数)Blob
构造函数) IE10支持MSBlobBuilder
和URL.createObjectURL
。但是,尝试从blob:
- URL创建Web Worker会引发SecurityError。
Opera 12不支持URL
API。由于this hack in browser.js
,有些用户可能会伪造URL
个对象。
Opera支持将数据URI作为Worker
构造函数的参数。注意:不要忘记escape special characters(例如#
和%
)。
// response as defined in the first example
var worker = new Worker('data:application/javascript,' +
encodeURIComponent(response) );
// ... Test as defined in the first example
演示:http://jsfiddle.net/uqcFM/37/
eval
可用作Safari(&lt; 6)和IE 10的后备广告。
// Worker-helper.js
self.onmessage = function(e) {
self.onmessage = null; // Clean-up
eval(e.data);
};
// Usage:
var worker = new Worker('Worker-helper.js');
// `response` as defined in the first example
worker.postMessage(response);
// .. Test as defined in the first example
答案 1 :(得分:5)
我同意当前接受的答案,但经常编辑和管理工作人员代码将会以字符串的形式出现。
所以我们可以选择使用下面的方法,我们可以将worker作为一个函数,然后转换为string-&gt; blob:
// function to be your worker
function workerFunction() {
var self = this;
self.onmessage = function(e) {
console.log('Received input: ', e.data); // message received from main thread
self.postMessage("Response back to main thread");
}
}
///////////////////////////////
var dataObj = '(' + workerFunction + ')();'; // here is the trick to convert the above fucntion to string
var blob = new Blob([dataObj.replace('"use strict";', '')]); // firefox adds "use strict"; to any function which might block worker execution so knock it off
var blobURL = (window.URL ? URL : webkitURL).createObjectURL(blob, {
type: 'application/javascript; charset=utf-8'
});
var worker = new Worker(blobURL); // spawn new worker
worker.onmessage = function(e) {
console.log('Worker said: ', e.data); // message received from worker
};
worker.postMessage("some input to worker"); // Send data to our worker.
这是在IE11 +和FF以及Chrome
中测试的答案 2 :(得分:3)
我已经用你的大多数想法做了一些方法并添加了我的一些想法。我的代码唯一需要的工作就是使用&#39;这个&#39;引用&#39; self&#39;范围。我非常确定这是非常可以改进的:
// Sample code
var code = function() {
this.onmessage = function(e) {
this.postMessage('Worker: '+e.data);
this.postMessage('Worker2: '+e.data);
};
};
// New thread worker code
FakeWorkerCode = function(code, worker) {
code.call(this);
this.worker = worker;
}
FakeWorkerCode.prototype.postMessage = function(e) {
this.worker.onmessage({data: e});
}
// Main thread worker side
FakeWorker = function(code) {
this.code = new FakeWorkerCode(code, this);
}
FakeWorker.prototype.postMessage = function(e) {
this.code.onmessage({data: e});
}
// Utilities for generating workers
Utils = {
stringifyFunction: function(func) {
// Stringify the code
return '(' + func + ').call(self);';
},
generateWorker: function(code) {
// URL.createObjectURL
windowURL = window.URL || window.webkitURL;
var blob, worker;
var stringified = Utils.stringifyFunction(code);
try {
blob = new Blob([stringified], {type: 'application/javascript'});
} catch (e) { // Backwards-compatibility
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
blob = new BlobBuilder();
blob.append(stringified);
blob = blob.getBlob();
}
if ("Worker" in window) {
worker = new Worker(windowURL.createObjectURL(blob));
} else {
worker = new FakeWorker(code);
}
return worker;
}
};
// Generate worker
var worker = Utils.generateWorker(code);
// Test, used in all examples:
worker.onmessage = function(e) {
alert('Response: ' + e.data);
};
function runWorker() {
worker.postMessage('working fine');
}
答案 3 :(得分:2)
由于支持向后兼容性,因此可接受的答案有点复杂,因此我想发布相同的内容,但简化了。在您的(现代)浏览器控制台中尝试以下操作:
const code = "console.log('Hello from web worker!')"
const blob = new Blob([code], {type: 'application/javascript'})
const worker = new Worker(URL.createObjectURL(blob))
// See the output in your console.
答案 4 :(得分:1)
很好的答案 - 当我们尝试创建具有后备功能的Web Workers时,我一直在研究类似的问题(即在主线程中运行工作程序脚本)。由于这个主题与主题有关,我想我会在这里提供我的解决方案:
<script type="javascript/worker">
//WORKER FUNCTIONS
self.onmessage = function(event) {
postMessage('Hello, ' + event.data.name + '!');
}
</script>
<script type="text/javascript">
function inlineWorker(parts, params, callback) {
var URL = (window.URL || window.webkitURL);
if (!URL && window.Worker) {
var worker = new window.Worker(URL.createObjectURL(new Blob([parts], { "type" : "text/javascript" })));
worker.onmessage = function(event) {
callback(event.data);
};
worker.postMessage(params);
} else {
var postMessage = function(result) {
callback(result);
};
var self = {}; //'self' in scope of inlineWorker.
eval(parts); //Converts self.onmessage function string to function on self via nearest scope (previous line) - please email chrisgwgreen.site@gmail.com if this could be tidier.
self.onmessage({
data: params
});
}
}
inlineWorker(
document.querySelector('[type="javascript/worker"]').textContent,
{
name: 'Chaps!!'
},
function(result) {
document.body.innerHTML = result;
}
);
</script>
</body>
答案 5 :(得分:1)
根据您的使用情况,您可以使用类似
的内容task.js 简化界面,让CPU密集型代码在所有核心(node.js和web)上运行
一个例子是
// turn blocking pure function into a worker task
const functionFromPostRequest = task.wrap('function (exampleArgument) {}');
// run task on a autoscaling worker pool
functionFromPostRequest('exampleArgumentValue').then(result => {
// do something with result
});
答案 6 :(得分:1)
扩展@Chanu_Sukarno的代码,你可以简单地将一个worker函数(或字符串)传递给这个函数,它将在web worker中执行它:
async function doWorkerTask(workerFunction, input, buffers) {
// Create worker
let fnString = '(' + workerFunction.toString().replace('"use strict";', '') + ')();';
let workerBlob = new Blob([fnString]);
let workerBlobURL = window.URL.createObjectURL(workerBlob, { type: 'application/javascript; charset=utf-8' });
let worker = new Worker(workerBlobURL);
// Run worker
return await new Promise(function(resolve, reject) {
worker.onmessage = function(e) { resolve(e.data); };
worker.postMessage(input, buffers);
});
}
以下是如何使用它的示例:
function myTask() {
self.onmessage = function(e) {
// do stuff with `e.data`, then:
self.postMessage("my response");
self.close();
}
}
let output = await doWorkerTask(myTask, input, inputBuffers);
// now you can do something with `output` (which will be equal to "my response")
在 nodejs 中,doWorkerTask
如下所示:
async function doWorkerTask(workerFunction, input, buffers) {
let Worker = require('webworker-threads').Worker;
let worker = new Worker(workerFunction);
// Run worker
return await new Promise(function(resolve, reject) {
worker.onmessage = function(e) { resolve(e.data); };
worker.postMessage(input, buffers);
});
}
答案 7 :(得分:0)
您可以通过将responseType
更改为"text"
或"arraybuffer"
来获取 objectURL 中的实际数据,而不仅仅是blob。
以下是text/javascript
至blob
至objectURL
的{em>来回转换,返回blob
或text/javascript
如果您想知道,我使用它来生成没有外部文件的网络工作者
您可以使用它来返回二进制内容,例如YouTube视频;)(来自&lt; video&gt;标记资源属性)
var blob = new Blob(['self.onmessage=function(e){postMessage(e)}'],{type: 'text/javascript'}); //->console: (object) Blob {size: 42, type: "text/javascript", slice: function}
var obju = URL.createObjectURL(js_blob); //->console: "blob:http%3A//stackoverflow.com/02e79c2b-025a-4293-be0f-f121dd57ccf7"
var xhr = new XMLHttpRequest();
xhr.open('GET', 'blob:http%3A//stackoverflow.com/02e79c2b-025a-4293-be0f-f121dd57ccf7', true);
xhr.responseType = 'text'; /* or "blob" */
xhr.onreadystatechange = function(){
if(xhr.DONE !== xhr.readyState) return;
console.log(xhr.response);
}
xhr.send();
/*
responseType "blob" ->console: (object) Blob {size: 42, type: "text/javascript", slice: function}
responseType "text" ->console: (text) 'self.onmessage=function(e){postMessage(e)}'
*/
答案 8 :(得分:-1)
使用我的小插件https://github.com/zevero/worker-create
var worker_url = Worker.create("self.postMessage('Example post from Worker');");
var worker = new Worker(worker_url);
但你也可以给它一个功能。