javascript - descargar - Trabajadores de la web que terminan abruptamente
void(0) javascript href (3)
Inicié un trabajador web en Chrome y tenía una función simple a la que se llamaba repetidamente usando setTimeout
. Sorprendentemente, el trabajador web finalizó después de que la función se llamara alrededor de 1000 veces. ¿Alguien puede explicar por qué? Creo que Chrome está haciendo algo de optimización.
webworker.js
function hi() {
postMessage(''1'');
setTimeout(hi, 1);
}
hi();
main.js
var blob = new Blob([code]);
var blobURL = window.URL.createObjectURL(blob);
var worker = new Worker(blobURL);
worker.onmessage = function(data) {
console.log(data.data); // gets called around 1000 times and done
};
EDITAR: Reproducido en un violín: http://jsfiddle.net/meovfpv3/1/ Parece que toma mucho tiempo para que la devolución de llamada onmessage deje de disparar, tan rápido como unos segundos y tan largo como +5 minutos
¿Estás tratando de publicar mensajes cada 1 ms? Entonces probablemente setInterval()
usar setInterval()
:
setInterval(function(){
postMessage(''1'');
}, 1);
Editar: incorrectamente vi recurrencia que no estaba allí, solo porque lo estaba buscando. Todavía usaría setInterval
sobre setTimeout
.
Aquí está mi mejor estimación de lo que está sucediendo. Al publicar un mensaje de Web Worker cada 1 ms, está exigiendo que el hilo principal procese cada mensaje publicado en 1 ms.
Si el hilo principal no puede procesar el mensaje dentro de 1 ms, aún está enviándole un mensaje nuevo aunque no haya terminado de procesar el último mensaje. Me imagino que esto lo pone en una cola de mensajes esperando ser procesados.
Ahora que está enviando mensajes del trabajador web más rápido de lo que se pueden procesar, esta cola de mensajes no procesados se hará cada vez más grande. En algún momento, Chrome levantará las manos y dirá "Hay demasiados mensajes en la cola", y en lugar de poner en cola nuevos mensajes para su procesamiento, los descartará.
Esta es la razón por la cual si usa un número razonable en su tiempo de espera como 100 ms, el mensaje tiene mucho tiempo para procesarse antes de que se envíe el siguiente mensaje, y no ocurre ningún problema con los mensajes no procesados.
Creé un jsFiddle donde el trabajador envía un mensaje al hilo principal y el hilo principal envía el mensaje al trabajador. Si ese proceso no ocurre antes de que se envíe el siguiente mensaje, los contadores en ambos hilos serán desiguales y el trabajador web finalizará.
http://jsfiddle.net/meovfpv3/3/
Puede ver que con un setTimeout razonable de 100 ms, todos los mensajes tienen tiempo suficiente para procesar antes de que se produzca el siguiente mensaje.
Cuando baje setTimeout a 1ms, la cadena de mensajes no tiene tiempo para terminar antes de que se envíe el siguiente mensaje y los contadores en cada hilo finalmente se desyoden, disparando la cláusula if
y terminando al trabajador web.
Una forma de solucionar este problema es, en lugar de publicar un mensaje a ciegas cada 1 ms, si el último se ha procesado o no, solo publicar un mensaje nuevo después de haber recibido un mensaje del hilo principal. Esto significa que solo está publicando mensajes tan rápido como el hilo principal puede procesarlos.
Para completar esto, hay una copia del código JSFiddle :
Obrero:
var counter2 = 0;
var rcvd = true;
function hi() {
counter2++;
console.log("")
console.log("postMessage", counter2)
postMessage(counter2);
if (!rcvd) {
self.close();
console.log("No message received");
}
rcvd = false;
setTimeout(hi, 1);
}
hi();
onmessage = function(e) {
rcvd = true;
console.log("secondMessage", e.data);
}
Principal:
var ww = document.querySelector(''script[type="text/ww"]''),
code = ww.textContent,
blob = new Blob([code], {type: ''text/javascript''}),
blobUrl = URL.createObjectURL(blob),
worker = new Worker(blobUrl),
counter = 0;
worker.onmessage = function(e) {
counter++;
console.log("onmessage:", counter);
worker.postMessage(e.data);
}
En primer lugar, un par de observaciones, que no puedo explicar, pero que son interesantes y pueden inspirar a alguien:
@Anson: si coloco tu código jsFiddle en Codepen (todavía en Chrome) no hay problemas allí. ¡La
onmessage
llamadaonmessage
simplemente sigue funcionando!Y de vuelta en jsFiddle ... Incluso falla al cambiar el
setTimeout
a un espacio largo como 10s, por lo que no es la cantidad de veces que el trabajador publica un mensaje, sino cuánto tiempo antes de que laonmessage
llamada deje de disparar, lo que tiene mucha variación.
Luego encontré algunas formas de mantener vivo el controlador onmessage
en este ejemplo específico:
- Agregue un botón / enlace en el html y un controlador (utilicé jQuery) que terminará al trabajador al hacer clic. Solo agregar este código lo corrige.
$("#stop").on("click",function(e){e.preventDefault();worker.terminate();});
- Simplemente agregue
console.log(worker)
después de definironmessage
. - Inspirado por una respuesta publicada en la pregunta relacionada , también puede simplemente agregar
window.worker = worker
después de definironmessage
.
Algo sobre volver a mencionar worker
en todos los casos parece mantenerlo vivo.