Jak mogę użyć funkcji tworzenia pracownika sieci Web na podstawie ciągu (który jest dostarczany za pośrednictwem żądania POST)?
Jednym ze sposobów, które przychodzą mi do głowy, ale nie jestem pewien, jak to zaimplementować, jest utworzenie identyfikatora URI danych z odpowiedzi serwera i przekazanie go do konstruktora Worker, ale słyszałem, że niektóre przeglądarki nie pozwalają to z powodu tej samej polityki pochodzenia.
MDN stwierdza niepewność co do polityki pochodzenia w odniesieniu do identyfikatorów URI danych :
Uwaga: identyfikator URI przekazany jako parametr konstruktora procesu roboczego musi być zgodny z zasadami tego samego pochodzenia. Wśród sprzedawców przeglądarek istnieje obecnie różnica zdań co do tego, czy identyfikatory URI danych są tego samego pochodzenia, czy też nie; Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0) i nowsze zezwalają na identyfikatory URI danych jako poprawny skrypt dla pracowników. Inne przeglądarki mogą się z tym nie zgadzać.
Tutaj jest również post omawiający to na whatwg .
źródło
Odpowiedzi:
URL.createObjectURL(<Blob blob>)
może służyć do tworzenia pracownika sieci Web z łańcucha. Obiekt BLOB można utworzyć przy użyciu przestarzałegoBlobBuilder
interfejsu API lub konstruktora .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');
Zgodność
Pracownicy sieciowi są obsługiwani w następujących źródłach przeglądarek :
Obsługa tej metody opiera się na wsparciu
Blob
API iURL.createObjectUrl
metody.Blob
kompatybilność :WebKitBlobBuilder
), 20+ (Blob
konstruktor)MozBlobBuilder
), 13+ (Blob
konstruktor)Blob
konstruktor)IE10 obsługuje
MSBlobBuilder
iURL.createObjectURL
. Jednak próba utworzenia elementublob:
roboczego sieci Web z -URL generuje błąd SecurityError.Opera 12 nie obsługuje
URL
API. Niektórzy użytkownicy mogą mieć fałszywą wersjęURL
obiektu, dzięki temu włamaniubrowser.js
.Powrót 1: identyfikator URI danych
Opera obsługuje identyfikatory URI danych jako argument dla
Worker
konstruktora. Uwaga: nie zapomnij o ucieczce znaków specjalnych (takich jak#
i%
).// 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
może być używany jako rozwiązanie zastępcze dla Safari (<6) i 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
źródło
MSBlobBuilder
iURL.createObjectURL
. Jednak próba utworzenia Webblob:
Workera z -URL generuje SecurityError.”. Tak więc dodanie nieMSBlobBuilder
przyniesie żadnego efektu, jedyną opcją jest rozwiązanie zastępcze nr 2.URL
(i dlatego też nie definiuje żadnych właściwości), a konstruktor Blob jest obecnie wystarczająco dobrze obsługiwany.data:
-URIs for Web Workers są również obsługiwane w przeglądarce Firefox, ale nie w przeglądarce Chrome ani Opera 15+. Wydajnośćeval
nie ma znaczenia, nie będziesz tworzyć milionów pracowników sieci Web na sekundę.Zgadzam się z obecnie akceptowaną odpowiedzią, ale często edycja i zarządzanie kodem pracownika będzie gorączkowe, ponieważ ma postać ciągu.
Więc opcjonalnie możemy użyć poniższego podejścia, w którym możemy zachować proces roboczy jako funkcję, a następnie ukryć go w 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.
Jest to testowane w IE11 +, FF i Chrome
źródło
Zrobiłem podejście do większości twoich pomysłów i dodałem kilka moich. Jedyną rzeczą, jakiej potrzebuje mój kod od pracownika, jest użycie „this” do określenia zakresu „self”. Jestem prawie pewien, że można to poprawić:
// 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/
źródło
Przyjęta odpowiedź jest nieco złożona ze względu na obsługę wstecznej kompatybilności, więc chciałem opublikować to samo, ale uproszczone. Spróbuj tego w swojej (nowoczesnej) konsoli przeglądarki:
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.
źródło
Dobra odpowiedź - pracowałem dzisiaj nad podobnym problemem, próbując stworzyć Web Workery z możliwościami rezerwowymi, gdy są one niedostępne (tj. Uruchom skrypt roboczy w głównym wątku). Ponieważ ten wątek dotyczy tematu, pomyślałem, że przedstawię tutaj swoje rozwiązanie:
<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>
źródło
W zależności od przypadku użycia możesz użyć czegoś takiego jak
Przykładem może być
// 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 });
źródło
Rozwijając kod @ Chanu_Sukarno, możesz po prostu przekazać funkcję roboczą (lub ciąg znaków) do tej funkcji, a ona wykona ją wewnątrz pracownika sieci:
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); }); }
Oto przykład, jak go używać:
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")
W nodejs ,
doWorkerTask
wygląda następująco: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); }); }
źródło
Możesz uzyskać rzeczywiste dane z objectURL, a nie tylko blob, zmieniając na
responseType
albo"text"
lub"arraybuffer"
.Oto konwersja w przód iw tył z
text/javascript
nablob
zobjectURL
powrotem nablob
lubtext/javascript
.jeśli się zastanawiasz, używam go do generowania pracownika sieciowego bez zewnętrznych plików
, możesz go użyć do zwrócenia zawartości binarnej, na przykład wideo z YouTube;) (z atrybutu zasobu tagu <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)}' */
źródło
Użyj mojej małej wtyczki https://github.com/zevero/worker-create
var worker_url = Worker.create("self.postMessage('Example post from Worker');"); var worker = new Worker(worker_url);
Ale możesz też nadać mu funkcję.
źródło