Wie kann ich einen Web-Worker aus einer Zeichenfolge erstellen (die über eine POST-Anforderung bereitgestellt wird)?
Eine Möglichkeit, die ich mir vorstellen kann, aber ich bin nicht sicher, wie ich sie implementieren soll, besteht darin, einen Daten-URI aus der Serverantwort zu erstellen und diesen an den Worker-Konstruktor zu übergeben, aber ich habe gehört, dass einige Browser dies nicht zulassen dies aufgrund der gleichen Ursprungspolitik.
MDN gibt die Unsicherheit über die Ursprungspolitik in Bezug auf Daten-URIs an :
Hinweis: Der als Parameter des Worker-Konstruktors übergebene URI muss der Richtlinie mit demselben Ursprung entsprechen. Derzeit gibt es unter den Anbietern von Browsern Meinungsverschiedenheiten darüber, ob Daten-URIs denselben Ursprungs sind oder nicht. Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0) und höher erlauben Daten-URIs als gültiges Skript für Worker. Andere Browser sind möglicherweise anderer Meinung.
Hier ist auch ein Beitrag , der es auf dem whatwg diskutiert .
quelle
Antworten:
URL.createObjectURL(<Blob blob>)
kann verwendet werden, um einen Web-Worker aus einer Zeichenfolge zu erstellen. Der Blob kann mit der veraltetenBlobBuilder
API oder dem Konstruktor erstellt werden .Blob
Demo: 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');
Kompatibilität
Web Arbeiter sind in der folgenden Browsern unterstützt Quelle :
Die Unterstützung dieser Methode basiert auf der Unterstützung der
Blob
API und derURL.createObjectUrl
Methode.Blob
Kompatibilität :WebKitBlobBuilder
), 20+ (Blob
Konstruktor)MozBlobBuilder
), 13+ (Blob
Konstruktor)Blob
Konstruktor)IE10 unterstützt
MSBlobBuilder
undURL.createObjectURL
. Beim Versuch, einen Web Worker aus einerblob:
-URL zu erstellen, wird jedoch ein SecurityError ausgelöst.Opera 12 unterstützt keine
URL
API. Einige Benutzer haben möglicherweise eine gefälschte Version desURL
Objekts, dank dieses Hack-Insbrowser.js
.Fallback 1: Daten-URI
Opera unterstützt Daten-URIs als Argument für den
Worker
Konstruktor. Hinweis: Vergessen Sie nicht, Sonderzeichen (wie#
und%
) zu maskieren .// response as defined in the first example var worker = new Worker('data:application/javascript,' + encodeURIComponent(response) ); // ... Test as defined in the first example
Demo: http://jsfiddle.net/uqcFM/37/
Fallback 2: Eval
eval
kann als Fallback für Safari (<6) und IE 10 verwendet werden.// 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
quelle
MSBlobBuilder
undURL.createObjectURL
. Wenn Sie jedoch versuchen, einen Web Worker aus einerblob:
-URL zu erstellen, wird ein SecurityError ausgelöst.". Das HinzufügenMSBlobBuilder
hat also keine Auswirkung. Die einzige Option ist Fallback Nr. 2.URL
(und damit auch keine Eigenschaften), und der Blob-Konstruktor wird heutzutage gut genug unterstützt.data:
-URIs für Web Worker werden auch in Firefox unterstützt, jedoch nicht in Chrome oder Opera 15+. Die Leistung voneval
ist nicht relevant. Sie werden nicht Millionen von Web-Mitarbeitern pro Sekunde erstellen.Ich stimme der derzeit akzeptierten Antwort zu, aber häufig ist das Bearbeiten und Verwalten des Worker-Codes hektisch, da er in Form einer Zeichenfolge vorliegt.
Optional können wir also den folgenden Ansatz verwenden, bei dem wir den Worker als Funktion behalten und dann zu string-> blob verdecken können:
// 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.
Dies wird in IE11 + und FF und Chrome getestet
quelle
Ich habe mit den meisten Ihrer Ideen einen Ansatz gewählt und einige von meinen hinzugefügt. Das einzige, was mein Code für Worker benötigt, ist, "this" zu verwenden, um auf "self" zu verweisen. Ich bin mir ziemlich sicher, dass dies sehr verbesserungsfähig ist:
// 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'); }
Demo: http://jsfiddle.net/8N6aR/
quelle
Gute Antwort - Ich habe heute an einem ähnlichen Problem gearbeitet, als ich versucht habe, Web Worker mit Fallback-Funktionen zu erstellen, wenn diese nicht verfügbar sind (dh Worker-Skript im Hauptthread ausführen). Da sich dieser Thread auf das Thema bezieht, dachte ich, ich würde hier meine Lösung anbieten:
<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 [email protected] 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>
quelle
Abhängig von Ihrem Anwendungsfall können Sie so etwas wie verwenden
Ein Beispiel wäre
// 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 });
quelle
Wenn Sie den Code von @ Chanu_Sukarno erweitern, können Sie einfach eine Worker-Funktion (oder einen String) an diese Funktion übergeben und sie wird in einem Web-Worker ausgeführt:
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); }); }
Hier ist ein Beispiel für die Verwendung:
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")
In NodeJS ,
doWorkerTask
sieht wie folgt aus :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); }); }
quelle
Die akzeptierte Antwort ist aufgrund der Unterstützung der Abwärtskompatibilität etwas komplex, daher wollte ich dasselbe posten, aber vereinfacht. Versuchen Sie dies in Ihrer (modernen) Browserkonsole:
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.
quelle
Sie können reale Daten von der objectURL abrufen und nicht nur durch Ändern
responseType
von entweder"text"
oder"arraybuffer"
.Hier ist eine Hin- und Her-Konvertierung von
text/javascript
zublob
zuobjectURL
zurück zublob
odertext/javascript
.Wenn Sie sich fragen, verwende ich es, um einen Web-Worker ohne externe Dateien zu generieren.
Sie können es verwenden, um binären Inhalt zurückzugeben, z. B. ein YouTube-Video;) (aus dem Attribut <video> -Tag-Ressource)
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)}' */
quelle
Verwenden Sie mein kleines Plugin https://github.com/zevero/worker-create
var worker_url = Worker.create("self.postMessage('Example post from Worker');"); var worker = new Worker(worker_url);
Sie können ihm aber auch eine Funktion geben.
quelle