如何从string创buildWeb Worker
我如何使用从string(通过POST请求提供)创buildWeb Worker?
我能想到的一种方式,但我不知道如何实现它,是从服务器响应创build一个数据URI,并将其传递给工人的构造函数,但我听说有些浏览器不允许这是因为相同的来源政策。
MDN指出围绕数据URI的原始策略的不确定性 :
注意:作为Worker构造函数parameter passing的URI必须遵守同源策略。 浏览器供应商目前在数据URI是否是同源的方面存在分歧, Gecko 10.0(Firefox 10.0 / Thunderbird 10.0)及更高版本允许数据URI作为工作者的有效脚本。 其他浏览器可能会不同意。
这里也有一个post, 讨论它在whatwg 。
概要
blob:
适用于Chrome 8 +,Firefox 6 +,Safari 6.0+,Opera 15+data:application/javascript
的Opera 10.60 – 12eval
否则(IE 10+)
可以使用URL.createObjectURL(<Blob blob>)
从string创buildWeb Worker。 Blob可以使用BlobBuilder
API或Blob
构造函数来创build。
演示: 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工作人员在以下浏览器资源中得到支持:
- Chrome 3
- Firefox 3.5
- IE 10
- Opera 10.60
- Safari 4
此方法的支持基于Blob
API和URL.createObjectUrl
方法的支持。 Blob
兼容性 :
- Chrome 8+(
WebKitBlobBuilder
),20+(Blob
构造函数) - Firefox 6+(
MozBlobBuilder
),13+(Blob
构造函数) - Safari 6+(
Blob
构造函数)
IE10支持MSBlobBuilder
和URL.createObjectURL
。 但是,尝试从blob:
创buildWeb Worker blob:
-URL将引发SecurityError。
Opera 12不支持URL
API。 有些用户可能有一个假的版本的URL
对象,这要归功于browser.js
这个黑客 。
回退1:数据URI
Opera支持将数据URI作为Worker
构造函数的参数。 注意:不要忘记转义特殊字符 (如#
和%
)。
// 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/
备用2:评估
eval
可以用作Safari(<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
我同意当前接受的答案,但是经常编辑和pipe理工人代码将像string一样紧张。
因此,我们可以select使用下面的方法,将worker作为一个函数,然后转换为string-> 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中进行了testing
我已经用你的大部分想法做了一个方法,并添加了一些我的想法。 我的代码在worker上唯一需要的是使用'this'来引用'self'作用域。 我很确定这是非常可以改进的:
// 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'); }
演示: http : //jsfiddle.net/8N6aR/
很好的答案 – 我今天在尝试创build具有备用function的Web Workers时,他们不可用(即在主线程中运行工作者脚本)时,一直在处理类似的问题。 由于这个主题是关于这个话题,我想我会在这里提供我的解决scheme:
<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>
根据你的用例,你可以使用类似的东西
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 });
扩展@ Chanu_Sukarno的代码,你可以简单地将一个工作函数(或string)传递给这个函数,它将在一个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); }); }
你可以通过改变responseType
为"text"
或"arraybuffer"
来获得objectURL的实际数据,而不是blob。
这里是text/javascript
到blob
到objectURL
回到blob
或text/javascript
的来回转换 。
如果你想知道,我正在使用它来生成一个没有外部文件的networking工作者
您可以使用它来返回二进制内容,例如YouTubevideo;)(来自<video>标签资源属性)
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)}' */
使用我的小插件https://github.com/zevero/worker-create
var worker_url = Worker.create("self.postMessage('Example post from Worker');"); var worker = new Worker(worker_url);
但是你也可以给它一个函数。