Usar web workers

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

Nota: como de costumbre, los subprocesos en segundo plano, incluyendo los workers, no pueden manipular el DOM.  Si las acciones adoptadas por el subproceso en segundo plano tienen que dar lugar a cambios en el DOM, deben enviar mensajes a sus creadores para hacer ese trabajo.

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().

Nota: La URI pasada como parámetro del constructor del 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.

Nota: los scripts pueden ser descargados en cualquier orden, pero no se ejecutarán en el orden en que pasas los nombres de archivo a 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.

Prueba este ejemplo .

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);
};
Nota: los objetos que se introducen o se extraer de los workers no deben contener funciones o referencias cíclicas, ya que JSON no es compatible con ellas.

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

Consulta también

Etiquetas y colaboradores del documento

Colaboradores de esta página: inma_610, ajimix
Última actualización por: ajimix,