90 votes

Comment créer un Web Worker à partir d'une chaîne de caractères ?

Comment puis-je utiliser la création d'un Web worker à partir d'une chaîne de caractères (fournie par une requête POST) ?

Un moyen auquel je pense, mais je ne suis pas sûr de la façon de l'implémenter, est de créer un data-URI à partir de la réponse du serveur, et de le passer au constructeur du Worker, mais j'ai entendu dire que certains navigateurs ne l'autorisent pas, à cause de la politique de la même origine.

MDN fait part de son incertitude quant à la politique d'origine des URI de données. :

Note : L'URI passé en paramètre du constructeur du Worker doit obéir à la politique de same-origin. Il existe actuellement un désaccord entre les fournisseurs de navigateurs sur la question de savoir si les URI de données sont de même origine ou non ; Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0) et les versions ultérieures autorisent les URI de données comme script valide pour les travailleurs. D'autres navigateurs peuvent ne pas être d'accord.

Voici également un post en discuter sur le whatwg .

0 votes

Je me demande si CORS ( w3.org/TR/cors ) serait utile. HTMl5rocks utilise un langage fort "doit" lorsqu'il s'agit de la politique de même origine pour les travailleurs ( html5rocks.com/fr/tutoriels/travailleurs/éléments de base ) donc peut-être que CORS n'est pas d'une grande aide ici. L'avez-vous essayé ?

1voto

Chad Scira Points 1839

En fonction de votre cas d'utilisation, vous pouvez utiliser quelque chose comme

task.js Interface simplifiée pour l'exécution de code à forte intensité de 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
});

1voto

En développant le code de @Chanu_Sukarno, vous pouvez simplement passer une fonction de travail (ou une 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")


En nodejs , doWorkerTask ressemble à ça :

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);
  });
}

0voto

Fabi Fabi Points 1

Ma solution (peut être "promise" facilement...)

   function makeWorker(workerFunction, cb) {
        // Create worker
        var tplFun = "onmessage = function(e){console.log(e);   var args = Array.prototype.slice.call(e.data); var res=___.apply(this,args);postMessage(res);}"
        var fnTxt = workerFunction.toString().replace('"use strict";', '');
        var final = tplFun.replace("___", fnTxt);
        let workerBlob = new Blob([final]);
        let workerBlobURL = window.URL.createObjectURL(workerBlob, { type: 'application/javascript; charset=utf-8' });
        let worker = new Worker(workerBlobURL);
        return function () {
            var args = Array.prototype.slice.call(arguments);
            console.log(args)
            worker.postMessage(args);
            worker.onmessage = function (e) {
                console.log(e.data);
                cb(e.data);
            }
        }
    }

    function myTask(a, b, c) {
        return a * b * c;
    }

    function onresult(e) {
        alert(e);
    }
    var fn = makeWorker(myTask, onresult)
    fn(1, 2, 3);

Peut être agréable avec la fonction "pure et lente" !

0voto

nicopowa Points 311

Basé sur la réponse acceptée, de la classe au travailleur, sujet intéressant.

// worker class
class SimpleWorker {

    constructor() {
        console.log("simple worker init");
    }

    onMessage(event) {
        console.log("main to worker", event.data);

        postMessage({
            type: "answer", 
            data: "data from worker"
        });

    }

}

// class to worker
const workerFromClass = workerClassRef => {

    console.log(workerClassRef.name, "to worker");

    // factory method, converted to string, used to instanciate worker
    let workerFactory = (self, workerClass) => {

        let worker = new workerClass();
        self["onmessage"] = worker.onMessage.bind(worker);

    };

    // compute worker code string
    // worker class & factory function
    let str = workerClassRef.toString() + "\n"
        + "(" + workerFactory.toString() + ")" 
        + "(this," + workerClassRef.name + ");"

    // worker code to blob
    let blob = new Blob(
        [str], 
        {type: "application/javascript"}
    );

    // return worker instance
    return new Worker(
        URL.createObjectURL(blob)
    );

};

// main
// create worker
let worker = workerFromClass(SimpleWorker);

// handle messages from worker
worker.addEventListener(
    "message", 
    event => console.log("worker to main", event.data)
);

// send message to worker
let message = {
    type: "question", 
    data: "data from main"
};
console.log("main to worker", message);
worker.postMessage(message);

-1voto

Vous pouvez obtenir des données réelles à partir du objetURL et pas seulement blob en changeant le responseType soit "text" o "arraybuffer" .

Voici un conversion en va-et-vient de text/javascript a blob a objectURL retour à blob o text/javascript .

<em>si vous vous posez la question, je l'utilise pour générer une <strong>web-worker sans fichiers externes</strong></em><br><em>vous pouvez l'utiliser pour renvoyer un contenu binaire, par exemple une vidéo YouTube ;) (à partir de l'attribut de ressource de la balise <video>)</em>

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)}'
*/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X