¿Cómo puedo crear una Web trabajador de una cadena (que se suministra a través de una solicitud POST)?

Una forma en que puedo pensar, pero no estoy seguro de cómo ponerlo en práctica, es mediante la creación de una base de datos-URI de la respuesta del servidor, y de paso que para el Trabajador constructor, pero he escuchado que algunos navegadores no permiten esto, debido al origen mismo de la política.

MDN estados de la incertidumbre sobre el origen de la política en torno a los datos de URI:

Nota: La URI que se pasa como parámetro del Trabajador constructor debe obedecer a la política de mismo origen. Actualmente, existe un desacuerdo entre los navegadores de los vendedores de si los datos URIs son del mismo origen o no; Gecko 10.0 (Firefox 10.0 /Thunderbird 10.0) y luego permitir que los datos Uri como una secuencia de comandos válida para los trabajadores. Otros navegadores pueden no estar de acuerdo.

Aquí también un post discutiendo en el whatwg.

Me pregunto si CORS (w3.org/TR/cors), sería de ayuda. HTMl5rocks usos fuerte «debe» del lenguaje cuando se trata de un mismo origen de la política para los trabajadores (html5rocks.com/en/tutorials/workers/basics) así que tal vez CORS no es de mucha ayuda aquí. No lo has probado?

OriginalEl autor bigblind | 2012-04-27

8 Comentarios

  1. 121

    Resumen

    • blob: para Chrome 8+, Firefox 6+, Safari 6.0+, Opera 15+
    • data:application/javascript de Opera 10.60 – 12
    • eval lo contrario (es decir 10+)

    URL.createObjectURL(<Blob blob>) puede ser utilizado para crear una Web trabajador de una cadena. El blob puede ser creado utilizando el BlobBuilder API obsoleto o el Blob constructor.

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

    Compatibilidad

    Web de los trabajadores en los siguientes navegadores fuente:

    • Chrome 3
    • Firefox 3.5
    • Es decir, 10
    • Opera 10.60
    • Safari 4

    Este método de apoyo se basa en el apoyo de la Blob de la API y el URL.createObjectUrl método. Blob compatibilidad:

    • Chrome 8+ (WebKitBlobBuilder), 20+ (Blob constructor)
    • Firefox 6+ (MozBlobBuilder), 13+ (Blob constructor)
    • Safari 6+ (Blob constructor)

    IE10 apoya MSBlobBuilder y URL.createObjectURL. Sin embargo, tratando de crear una Web Trabajador de una blob:-URL lanza un SecurityError.

    Opera 12 no admite URL de la API. Algunos usuarios pueden tener una versión falsa de la URL objeto, gracias a este hack en browser.js.

    De reserva 1: datos-URI

    De la ópera de soportes de datos-URIs como un argumento a la Worker constructor. Nota: no te olvides de escapar los caracteres especiales (como # y %).

    //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/

    De Reserva 2: Eval

    eval puede ser utilizado como una reserva para Safari (<6) y el 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
    Gracias por tu edición, pero no es necesario. Si se mira un par de líneas más, vas a ver «IE10 apoya MSBlobBuilder y URL.createObjectURL. Sin embargo, tratando de crear una Web Trabajador de una blob:-URL lanza un SecurityError.». Así, la adición de MSBlobBuilder no tendrá ningún efecto, la única opción es la de reserva de #2.
    Opera 12 ya no se define URL (y, por tanto, no se define ninguna de las propiedades), y la mancha constructor es hoy en día bastante bien apoyado.
    He comprobado que esto todavía sucede en IE11, al menos en la vista previa.
    Son dataURIs apoyado sólo en la Ópera o en el resto de navegadores (excepto IE)?
    data:-URIs para la Web de los Trabajadores que se apoya también en Firefox, pero no en Chrome o Opera 15+. El rendimiento de eval no es relevante, no vas a crear millones de Web los trabajadores por segundo.

    OriginalEl autor Rob W

  2. 5

    Estoy de acuerdo con el actual aceptado la respuesta, sino que a menudo editar y gestionar el código del trabajador será agitada como en la forma de una cadena.

    Así opcionalmente podemos utilizar el siguiente planteamiento en el que puede mantener al trabajador como una función, y luego convertir a 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.

    Esto es probado en IE11+ y FF y Chrome

    Como esto no es un wiki de la comunidad post, debe exponer los posibles problemas para el cartel a través de un comentario en lugar de una edición.
    Lo siento. Tuve que hacer que trabajar en IE11 con los cambios que hice. @ ChanuSukarno Podría usted por favor, compruebe si los cambios en la revisión 3 está bien?

    OriginalEl autor Chanakya Vadla

  3. 3

    He hecho un acercamiento con la mayoría de sus ideas y la adición de algunos de los míos. La única cosa que mi código necesidades de los trabajadores es el uso de ‘esta’ para referirse a la «auto’ alcance. Estoy bastante seguro de que esto es muy mejorables:

    //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/

    Esto no funciona en IE10

    OriginalEl autor lukelalo

  4. 1

    Bonita respuesta – he estado trabajando en un problema similar hoy en día cuando se trata de crear Web de Trabajadores con reserva de capacidades cuando no están disponibles (es decir, ejecutar el script del trabajador en el hilo principal). Como este hilo se refiere al tema, he pensado que me gustaría dar mi solución aquí:

        <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>

    OriginalEl autor Chris GW Green

  5. 1

    Dependiendo de su caso de uso se puede usar algo como

    task.js Interfaz simplificada para la obtención de la CPU a la ejecución de código en todos los núcleos (node.js y web)

    Un ejemplo sería

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

    OriginalEl autor Chad Scira

  6. 1

    Ampliando @Chanu_Sukarno del código, usted puede simplemente pasar un trabajador de la función (o cadena) para esta función que se ejecutará dentro de un 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);
    });
    }

    He aquí un ejemplo de cómo usarlo:

    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 se parece a esto:

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

    OriginalEl autor

  7. 0

    Usted puede obtener los datos de la objectURL y no sólo blob cambiando el responseType a "text" o "arraybuffer".

    Aquí es un de ida y vuelta a la conversión de text/javascript a blob a objectURL de vuelta a blob o text/javascript.

    si usted se está preguntando, lo estoy usando para generar un web-trabajador sin archivos externos

    puede utilizar para devolver el contenido binario, por ejemplo un vídeo de YouTube 😉 (de la <video> etiqueta de atributo de recurso)

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

    OriginalEl autor

Dejar respuesta

Please enter your comment!
Please enter your name here