javascript - tablas - Cómo crear un trabajador web a partir de una cadena
obtener datos de una tabla html javascript (8)
Resumen
blob:
para Chrome 8+, Firefox 6+, Safari 6.0+, Opera 15+data:application/javascript
para Opera 10.60 - 12eval
contrario (IE 10+)
URL.createObjectURL(<Blob blob>)
se puede usar para crear un trabajador web a partir de una cadena. El blob se puede crear usando la API BlobBuilder
desuso o el constructor Blob
.
Demostración: 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
Los trabajadores web son compatibles en la siguiente source navegadores:
- Chrome 3
- Firefox 3.5
- IE 10
- Opera 10.60
- Safari 4
El soporte de este método se basa en el soporte de la API Blob
y el método URL.createObjectUrl
. Compatibilidad Blob
:
- Chrome 8+ (
WebKitBlobBuilder
), 20+ (constructorBlob
) - Firefox 6+ (
MozBlobBuilder
), 13+ (constructorBlob
) - Safari 6+ (constructor
Blob
)
IE10 es compatible con MSBlobBuilder
y URL.createObjectURL
. Sin embargo, al tratar de crear un Trabajador web a partir de un blob:
-URL arroja un SecurityError.
Opera 12 no es compatible con API de URL
. Algunos usuarios pueden tener una versión falsa del objeto URL
, gracias a este truco en browser.js
.
Fallback 1: URI de datos
Opera admite URI de datos como argumento para el constructor Worker
. Nota: No olvides escapar 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
Demostración: http://jsfiddle.net/uqcFM/37/
Fallback 2: Evaluar
eval
se puede usar como respaldo para Safari (<6) e 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
¿Cómo puedo usar crear un trabajador web a partir de una cadena (que se proporciona a través de una solicitud POST)?
Una forma en que puedo pensar, pero no estoy seguro de cómo implementarlo, es creando un URI de datos a partir de la respuesta del servidor, y pasándolo al constructor Worker, pero he oído que algunos navegadores no permiten esto, debido a la misma política de origen.
MDN declara la incertidumbre sobre la política de origen en torno a los URI de datos :
Nota: El URI pasado como parámetro del constructor Worker debe obedecer a la política del mismo origen. Actualmente existe un desacuerdo entre los proveedores de navegadores sobre si los URI de datos son del mismo origen o no; Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0) y luego permite URI de datos como un script válido para los trabajadores. Otros navegadores pueden estar en desacuerdo.
Aquí también hay una publicación discutiéndolo en el whatwg .
Ampliando el código de @ Chanu_Sukarno, simplemente puede pasar una función de trabajador (o cadena) a esta función y la ejecutará dentro de un trabajador 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);
});
}
Aquí hay 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
ve así:
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);
});
}
Buena respuesta: he estado trabajando en un problema similar hoy cuando trato de crear Web Workers con capacidades de respaldo cuando no están disponibles (es decir, ejecutar script de trabajador en el hilo principal). Como este hilo pertenece al tema, pensé que proporcionaría 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>
Dependiendo de su caso de uso, puede usar algo como
task.js Interfaz simplificada para hacer que el código intensivo de la CPU se ejecute 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
});
Estoy de acuerdo con la respuesta aceptada actual, pero a menudo la edición y la administración del código de trabajador serán agitadas ya que se trata de una cadena.
Entonces, opcionalmente, podemos usar el siguiente enfoque donde podemos mantener al trabajador como una función, y luego convertirlo 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 se prueba en IE11 + y FF y Chrome
Formulé un enfoque con la mayoría de sus ideas y agregué algunas de las mías. Lo único que mi código necesita del trabajador es usar ''esto'' para referirse al ''alcance propio''. Estoy bastante seguro de que esto es muy mejorable:
// 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'');
}
Demostración: http://jsfiddle.net/8N6aR/
Puede obtener datos reales de objectURL y no solo blob cambiando el tipo de responseType
a "text"
o "arraybuffer"
.
Aquí hay una conversión ida y vuelta de text/javascript
a blob
a objectURL
a blob
o text/javascript
.
si se lo está preguntando, lo estoy usando para generar un trabajador web sin archivos externos
puede usarlo para devolver contenido binario, por ejemplo, un video de YouTube;) (del atributo de recurso de etiqueta <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//.com/02e79c2b-025a-4293-be0f-f121dd57ccf7"
var xhr = new XMLHttpRequest();
xhr.open(''GET'', ''blob:http%3A//.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)}''
*/
Use mi pequeño complemento https://github.com/zevero/worker-create
var worker_url = Worker.create("self.postMessage(''Example post from Worker'');");
var worker = new Worker(worker_url);
Pero también puedes darle una función.