Logotipo de Xitrus.
sígueme en facebook

Sígueme

R L E F G I

Buscar

Cargando

Lo último del blog

Hosting

Xitrus está alojado en:

Xitrus está alojado en Cyberneticos.
01
10

Aumenta el rendimiento de JavaScript con Web Worker

JavaScript nunca había sido un lenguaje donde procesar grandes cantidades de datos, pero HTML5 ha incorporado la API de Web Worker, que permite paralelizar procesos de JavaScript, ejecutándolos en segundo plano.

La principal ventaja de Web Worker es que nos permite crear subprocesos de nuestro hilo de ejecución principal, para poder procesar lo que queramos sin necesidad de bloquear el navegador y de una forma muy simple. Se podría decir que funciona de forma similar a AJAX.

API de Web Worker de HTML5.

Esta API funciona de forma asíncrona, disponiendo de dos métodos de uso. Nosotros solo nos centraremos en el que tiene compatibilidad con todos los navegadores modernos.
Este método consiste en cargar un archivo JavaScript que contiene todo el código que ejecutará el Web Worker, y nos comunicaremos con el enviándo mensajes que pueden contener cualquier dato. Desde el Worker para devolver los datos se usa el mismo método.

Introducción

A la API accedemos creando un objeto Web Worker, que en la práctica es Worker(). Solo veremos un par de métodos para interactuar con la API y la forma de responder ante un evento (es decir, el mensaje del Worker cuando nos proporcione un dato).
Tras crear el Worker podremos enviarle un mensaje mediante postMessage() o parar su ejecución mediante terminate()

  1. var worker = new Worker('worker.js'); // Ruta del archivo JavaScript

En este paso la API cargará el archivo de forma asíncrona, sin que haya ninguna ralentización en el navegador.

Ahora estableceremos que hacer cuando recibamos un mensaje de nuestro Worker. El evento que genera se llama "message".

  1. worker.addEventListener('message', function(e) {
  2. alert('Respuesta del Worker: ' + e.data);
  3. }, false);

En este caso cuando recibamos una respuesta del Worker saltará una alerta, pero podemos hacer cualquier cosa con los datos. Accedemos a la respuesta mandando el evento (en este caso e) a la función y cogiendo data.

Haremos un "hola mundo!" y que el Worker convertirá a mayúsculas.
Podemos mandar objetos o arrays, pero en este caso ejecutaremos el Worker, mandándole un mensaje con texto.

  1. worker.postMessage('hola mundo!');

Si queremos parar la ejecución del Worker debemos de hacer lo siguiente:

  1. worker.terminate();

Actuando desde el Worker

Tenemos que tener en cuenta que la llamada anterior la haremos a otro archivo, por lo tanto el siguiente script irá incorporado en ese otro archivo.

Antes, cuando interactuábamos con la API lo hacíamos con la variable worker (que contenía el objeto de la API), desde el archivo separado tenemos que interactuar con la API con self de prácticamente la misma forma que antes.

En el siguiente fragmento, al recibir el evento leeremos los datos que mandamos al Worker y los volvemos a mandar en mayúscula.

  1. self.addEventListener('message', function(e) {
  2. self.postMessage(e.data.toUpperCase());
  3. }, false);

Tras realizar este ejemplo deberíamos de recibir una alerta que indicase lo siguiente: "Respuesta del Worker: HOLA MUNDO!".

Prueba del funcionamiento

Para hacer una prueba para entender el funcionamiento asíncrono voy a realizar una función que realizará un cálculo, con y sin Worker. Cuando lo hagamos sin Worker debéis de intentar moveros por la página para notar la pérdida de fluidez, mientras que con el Worker no pasa esto.

Nota: si tarda en responder la página es normal.

Con Worker
Parado

Sin Worker
Parado

Esta es una de las ventajas, que nos ahorramos saturar el navegador y hacer que la experiencia de usuario decaiga por procesar grandes datos.

Paralelizar procesos

El poder paralelizar procesos es otro de los puntos fuertes de esta API, que permite eliminar el límite impuesto por ejecutar nuestro script en un solo proceso, que es el de solo ser procesado por un procesador (físico o lógico).
Antes de poneros a ver como se hace voy a poneros un ejemplo, donde podéis establecer el número de Workers que ejecutaremos. Si realizamos la prueba con un solo Worker veremos cuanto tiempo tarda en procesarse con un solo proceso (sin paralelizar), que sería el equivalente a no usar la API. Por el contrario, si ponéis el número de vuestros procesadores y miráis el administrador de tareas veréis como usa el 100% de la CPU.


Ejecutar

Tiempo

Para realizar la paralelización tenemos que tener en cuenta que el proceso que queremos hacer va a ser efectivo si lo paralelizamos.
En el caso de la prueba anterior se hacen cálculos con potencias de los números de un rango, en ese caso podemos divir el rango en porciones que ejecutaremos de forma paralela (si tenemos que hacer cálculos con los números del "0" al "99" podemos dividirlo del "0" al "49" y del "50" al "99", por poner un ejemplo).

Para paralelizar los Workers simplemente tenemos que llamar a varios a la vez, ya sea para un mismo proceso (como acabo de mencionar) o sea para procesos distintos. En el siguiente ejemplo llamaremos a dos Workers que se ejecutarán paralelamente.

  1. // Primer proceso
  2. var workerUno = new Worker('workerUno.js');
  3. workerUno.addEventListener('message', function(e) {
  4. alert('Respuesta del Worker: ' + e.data);
  5. }, false);
  6. workerUno.postMessage('hola mundo!');
  7. // Segundo proceso
  8. var workerDos = new Worker('workerDos.js');
  9. workerDos.addEventListener('message', function(e) {
  10. alert(e.data);
  11. }, false);
  12. workerDos.postMessage([50,100]);

Resumen

Esta API es una de las más simples de HTML5, y nos puede resultar familiar a AJAX, ya que se produce de forma asíncrona un intercambio de mensajes. A los Workers, además, se le pueden dar muchos usos como podrían ser: generar un Canvas, analizar un archivo de audio, procesar un archivo grande JSON y muchas cosas más.



Comentarios

Sígueme

R L E F G I

Buscar

Cargando

Lo último del blog

Hosting

Xitrus está alojado en:

Xitrus está alojado en Cyberneticos.
Cerrar sesión
Usuario: Contraseña: