Comment puis-je utiliser créer un travailleur Web à partir d'une chaîne (qui est fournie via une demande POST))?
Une façon de penser, mais je ne sais pas comment l'implémenter, est de créer un URI de données à partir de la réponse du serveur et de le transmettre au constructeur Worker, mais j'ai entendu dire que certains navigateurs ne permettent pas cela, en raison de la même politique d'origine.
MDN indique l'incertitude concernant la politique d'origine concernant les URI de données :
Remarque: L'URI transmis en tant que paramètre du constructeur Worker doit obéir à la même politique d'origine. Il existe actuellement un désaccord entre les fournisseurs de navigateurs quant à savoir si les URI de données sont de même origine ou non; Gecko 10.0 (Firefox 10.0/Thunderbird 10.0) et versions ultérieures autorisent les URI de données en tant que script valide pour les travailleurs. D'autres navigateurs peuvent ne pas être d'accord.
Voici également un article en discuter sur le whatwg .
Sommaire
blob:
Pour Chrome 8+, Firefox 6+, Safari 6.0+, Opera 15+data:application/javascript
Pour Opera 10.60 - 12eval
sinon (IE 10+)
URL.createObjectURL(<Blob blob>)
peut être utilisé pour créer un travailleur Web à partir d'une chaîne. Le blob peut être créé à l'aide de l'API BlobBuilder
obsolète ou le constructeur Blob
.
Démo: 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');
Les travailleurs Web sont pris en charge dans les navigateurs suivants source:
La prise en charge de cette méthode est basée sur la prise en charge de l'API Blob
et de la méthode URL.createObjectUrl
. Blob
compatibilité :
WebKitBlobBuilder
), 20+ (Blob
constructeur)MozBlobBuilder
), 13+ (Blob
constructeur)Blob
)IE10 prend en charge MSBlobBuilder
et URL.createObjectURL
. Cependant, essayer de créer un Web Worker à partir d'une blob:
- URL lève une SecurityError.
Opera 12 ne prend pas en charge l'API URL
. Certains utilisateurs peuvent avoir une fausse version de l'objet URL
, grâce à ce hack dans browser.js
.
Opera prend en charge les URI de données comme argument du constructeur Worker
. Remarque: N'oubliez pas de échapper les caractères spéciaux (comme #
Et %
).
// response as defined in the first example
var worker = new Worker('data:application/javascript,' +
encodeURIComponent(response) );
// ... Test as defined in the first example
Démo: http://jsfiddle.net/uqcFM/37/
eval
peut être utilisé comme solution de rechange pour Safari (<6) et 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
Je suis d'accord avec la réponse actuellement acceptée, mais souvent, la modification et la gestion du code du travailleur seront très complexes sous la forme d'une chaîne.
Donc, nous pouvons éventuellement utiliser l'approche ci-dessous où nous pouvons garder le travailleur en tant que fonction, puis convertir en 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.
Ceci est testé dans IE11 + et FF et Chrome
J'ai fait une approche avec la plupart de vos idées et en ajoutant certaines des miennes. La seule chose dont mon code a besoin sur le travailleur est d'utiliser "ceci" pour désigner la portée "soi". Je suis sûr que c'est très améliorable:
// 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');
}
En développant le code de @ Chanu_Sukarno, vous pouvez simplement passer une fonction de travail (ou chaîne) à cette fonction et elle l'exécutera dans un travailleur Web:
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);
});
}
Voici un exemple d'utilisation:
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")
Dans nodejs, doWorkerTask
ressemble à ceci:
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);
});
}
Bonne réponse - J'ai travaillé sur un problème similaire aujourd'hui en essayant de créer des Web Workers avec des capacités de secours lorsqu'ils ne sont pas disponibles (c'est-à-dire exécuter le script de travail dans le thread principal). Comme ce fil se rapporte au sujet, j'ai pensé apporter ma solution ici:
<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>
Selon votre cas d'utilisation, vous pouvez utiliser quelque chose comme
task.js Interface simplifiée pour faire fonctionner du code gourmand en CPU sur tous les cœurs (node.js et web)
Un exemple serait
// 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
});
Vous pouvez obtenir des données réelles à partir de objectURL et pas simplement blob en changeant le responseType
en _ "text"
ou "arraybuffer"
.
Voici une conversion de va-et-vient de text/javascript
à blob
à objectURL
retour à blob
ou text/javascript
.
si vous vous posez la question, je l'utilise pour générer un web-travailleur sans fichiers externes
vous pouvez l'utiliser pour renvoyer du contenu binaire, par exemple une vidéo YouTube;) (à partir de l'attribut de ressource de balise <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)}'
*/