如何从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 – 12
  • eval否则(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支持MSBlobBuilderURL.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/javascriptblobobjectURL回到blobtext/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); 

但是你也可以给它一个函数。