Workers constituye un medio sencillo para que el contenido web ejecute secuencias de comandos en subprocesos en segundo plano. Una vez creado, un worker puede enviar mensajes a la tarea de generación mediante la publicación de mensajes en un controlador de eventos especificado por el creador.
El subproceso del worker puede realizar tareas sin interferir con la interfaz de usuario. Además, pueden realizar E / S utilizando XMLHttpRequest
(aunque los atributos responseXML
y channel
siempre son nulos).
Consulta el documento de referencia Worker , al que este artículo complementa ofreciendo ejemplos y añadiendo detalles. Para obtener una lista de funciones disponibles para workers, consulta Funciones disponibles para workers .
Acerca de la seguridad en los subprocesos
La interfaz Worker
genera subprocesos a nivel del sistema operativo y la simultaneidad puede producir efectos interesantes en el código si no tienes cuidado. Sin embargo, en el caso de web workers, los puntos de comunicación controlados cuidadosamente con otros subprocesos supone que en realidad sea muy difícil causar problemas de simultaneidad. No hay acceso a componentes sin subprocesos seguros o al DOM y tienes que pasar datos específicos dentro y fuera de un subproceso a través de objetos serializados. Así que te tienes que esforzar mucho para causar problemas en el código.
Generar un worker
Crear un nuevo worker es simple. Lo único que tienes que hacer es llamar al constructor Worker()
, especificando el URI de un script para ejecutar en el subproceso del worker y, si deseas poder recibir las notificaciones del worker, establece la propiedad onmessage
del worker a una función de manejador de evento adecuada.
var myWorker = new Worker('my_worker.js'); myWorker.onmessage = function(event) { print("Llamado de nuevo por el worker\n"); };
De forma alternativa, podemos usar addEventListener()
:
var worker = new Worker('my_worker.js'); worker.addEventListener('message', function(event) { console.log("Called back by the worker!\n"); }, false); worker.postMessage(""); // Iniciar el worker.
La línea 1 de este ejemplo crea e inicia el subproceso del worker. La línea 2 establece el controlador onmessage
para el worker a una función que se llama cuando éste pide su propia función postMessage()
.
Worker
debe obedecer la política del mismo origen o same-origin policy. Actualmente hay un desacuerdo en los diferentes desarrolladores de navegadores acerca de si las URIs han de ser del mismo origen o no; Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0 / SeaMonkey 2.7) y posteriores permiten cualquier URI como script válido para workers, otros navegadores pueden no permitirlo.Generar subworkers
Los workers pueden generar más workers si así lo desean. Los llamados subworkers deben estar alojados en el mismo origen que la página principal. Además, los URI para los subworkers se resuelven en relación a la ubicación del worker principal y no en relación a la de la página propietaria. Esto hace que sea más fácil que los workers realicen un seguimiento de dónde están sus dependencias.
Tiempos de espera e intervalos
Los workers pueden utilizar los tiempos de espera y los intervalos al igual que el proceso principal. Esto puede ser útil, por ejemplo, si quieres hacer que tu subproceso del worker ejecute código de manera periódica en lugar de ininterrumpidamente.
Consulta setTimeout()
, clearTimeout()
, setInterval()
y clearInterval()
si deseas tener más detalles.
Terminar un worker
Si tienes que cancelar inmediatamente un worker que se está ejecutando, puedes hacerlo llamando al método terminate()
del worker:
myWorker.terminate();
El subproceso del worker se interrumpe inmediatamente y sin tener la posibilidad de terminar sus operaciones o limpiar por sí mismo.
Los workers pueden cerrarse llamando a su propio método nsIWorkerScope.close()
.
Gestión de errores
Cuando se produce un error de ejecución en el worker, es llamado su controlador de enventos onerror
. Recibe un evento denominado error
que implementa la interfaz ErrorEvent
. El evento no se lanza y se puede cancelar, para evitar que la acción predeterminada tenga lugar, el worker puede llamar al método preventDefault()
del evento de error.
El evento de error tiene los siguientes tres campos que son de interés:
-
message
- Un mensaje de error legible para el ojo humano.
-
filename
- El nombre del archivo de script en el que se produjo el error.
-
lineno
- El número de línea del archivo de script en el que se produjo el error.
Acceder al objeto navegador
Los workers pueden acceder al objeto navigator
, que está disponible dentro de su ámbito. Contiene las siguientes cadenas de texto que pueden usarse para identificar el navegador, tal y como se puede hacer a partir de secuencias de comandos normales:
appName
appVersion
platform
userAgent
Importar de secuencias de comandos y bibliotecas
Los subprocesos de trabajo tienen acceso a una función global, importScripts (), que les permite importar secuencias de comandos de comandos o bibliotecas dentro de su ámbito. Acepta como parámetros cero o más URI de recursos para la importación, todos los ejemplos siguientes son válidos:
importScripts(); /* no importa nada */ importScripts('foo.js'); /* importa solo "foo.js" */ importScripts('foo.js', 'bar.js'); /* importa dos scripts */
Firefox carga cada secuencia de comandos de la lista, luego los ejecuta para permitirles que se inicialicen ellos mismos. Los objetos globales de cada secuencia de comandos pueden entonces ser utilizados por el worker.
importScripts()
. Esto se realiza de forma sincrónica; importScripts()
no retorna hasta que todas las secuencias de comandos se han cargado y ejecutado.
Ejemplos
Esta sección incluye varios ejemplos de cómo utilizar los DOM workers.
Realizar cálculos en segundo plano
Una utilidad de los workers es permitir que tu código realice cálculos intensivos en el procesador sin bloquear el subproceso de interfaz de usuario. En este ejemplo, un worker se utiliza para calcular los números de Fibonacci.
El código JavaScript
var results = []; function resultReceiver(event) { results.push(parseInt(event.data)); if (results.length == 2) { postMessage(results[0] + results[1]); } } function errorReceiver(event) { throw event.data; } onmessage = function(event) { var n = parseInt(event.data); if (n == 0 || n == 1) { postMessage(n); return; } for (var i = 1; i <= 2; i++) { var worker = new Worker("fibonacci.js"); worker.onmessage = resultReceiver; worker.onerror = errorReceiver; worker.postMessage(n - i); } };
La función onmessage
es llamada cuando el código HTML llamada al postMessage()
en el worker. Esto inicia la recursividad, generando copias nuevas de sí mismo para controlar cada iteración del cálculo.
El código HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <title>Test threads fibonacci</title> <body> <div id="result"></div> <script language="javascript"> var worker = new Worker("fibonacci.js"); worker.onmessage = function(event) { document.getElementById("result").textContent = event.data; dump("Got: " + event.data + "\n"); }; worker.onerror = function(error) { dump("Worker error: " + error.message + "\n"); throw error; }; worker.postMessage("5"); </script> </body> </html>
La página web crea un elemento div
con el id. de cliente result
, que se utiliza para mostrar el resultado, a continuación, genera el worker. Tras generar el worker, el manejadoronmessage
está configurado para mostrar los resultados mediante el ajuste de los contenidos del elemento div
, y el manejador onerror
se establece para volcar el mensaje de error.
Por último, se envía un mensaje al worker para iniciarlo.
Realizar E / S de web en segundo plano
Puedes encontrar un ejemplo de esto en el artículo Usar workers en las extensiones .
Dividir tareas entre varios workers
A medida que los equipos con varios núcleos se hacen cada vez más frecuentes, resulta útil dividir las tareas complejas, desde el punto de vista computacional, entre varios workers, que a su vez pueden llevar a cabo esas tareas en núcleos de procesador múltiple.
el ejemplo se incluirá muy pronto
Crear workers desde dentro de los workers
El ejemplo de Fibonacci mostrado anteriormente demuestra que los workers pueden, de hecho, generar más workers. Esto facilita crear rutinas repetitivas.
Enviar objetos a los workers
Puede pasar con seguridad los objetos dentro y fuera de los workers que utilizan el método postMessage()
, los objetos se convierten automáticamente en JSON de manera interna.
var onmessage = function(e) { postMessage(e.data); };
Característica | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari (WebKit) |
---|---|---|---|---|---|
Workers dedicados | 3 | 3.5 (1.9.1) | 10 | 10.60 | 4 |
Workers compartidos | 5 | --- | --- | 10.60 | 5 |
Pasar datos usando clonación estructurada. | 13 | 8 | 10 | 11.50 | 5.1 |
Pasar datos usando objetos transferibles | 17 webkit | --- | --- | --- | --- |
Característica | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Phone | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Workers dedicados | --- | 0.16 | --- | --- | 11 | 5 |
Workers compartidos | --- | Not supported | --- | --- | --- | --- |
Pasar datos usando clonación estructurada. | --- | 0.16 | --- | --- | --- | --- |