w3schools tag tab page change javascript multithreading

javascript - tag - title of page html



JavaScript e hilos (13)

Diferente forma de hacer multi-threading y Asynchronous en JavaScript

Antes JavaScript HTML5 solo permitía la ejecución de un hilo por página.

Hubo alguna forma extravagante de simular una ejecución asincrónica con Yield , setTimeout() , setInterval() , XMLHttpRequest o controladores de eventos (consulte el final de esta publicación para ver un ejemplo con yield y setTimeout() ).

Pero con HTML5 ahora podemos usar Worker Threads para paralelizar la ejecución de funciones. Aquí hay un ejemplo de uso.

Real multi-threading

Multi-threading: hilos de trabajo de JavaScript

HTML5 introdujo Web Worker Threads (ver: http://caniuse.com/#search=worker )
Nota: IE9 y versiones anteriores no lo admiten.

Estos subprocesos de trabajo son subprocesos de JavaScript que se ejecutan en segundo plano sin afectar el rendimiento de la página. Para obtener más información sobre Web Worker, lea la documentación o este tutorial .

Aquí hay un ejemplo simple con 3 hilos de Web Worker que cuentan hasta MAX_VALUE y muestran el valor actual calculado en nuestra página:

//As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706 function getScriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^/s*function/s*/(/s*/)/s*/{(([/s/S](?!/}$))*[/s/S])/)[1]],{type:''text/javascript''})); } var MAX_VALUE = 10000; /* * Here are the workers */ //Worker 1 var worker1 = new Worker(getScriptPath(function(){ self.addEventListener(''message'', function(e) { var value = 0; while(value <= e.data){ self.postMessage(value); value++; } }, false); })); //We add a listener to the worker to get the response and show it in the page worker1.addEventListener(''message'', function(e) { document.getElementById("result1").innerHTML = e.data; }, false); //Worker 2 var worker2 = new Worker(getScriptPath(function(){ self.addEventListener(''message'', function(e) { var value = 0; while(value <= e.data){ self.postMessage(value); value++; } }, false); })); worker2.addEventListener(''message'', function(e) { document.getElementById("result2").innerHTML = e.data; }, false); //Worker 3 var worker3 = new Worker(getScriptPath(function(){ self.addEventListener(''message'', function(e) { var value = 0; while(value <= e.data){ self.postMessage(value); value++; } }, false); })); worker3.addEventListener(''message'', function(e) { document.getElementById("result3").innerHTML = e.data; }, false); // Start and send data to our worker. worker1.postMessage(MAX_VALUE); worker2.postMessage(MAX_VALUE); worker3.postMessage(MAX_VALUE);

<div id="result1"></div> <div id="result2"></div> <div id="result3"></div>

Podemos ver que los tres hilos se ejecutan en concurrencia e imprimir su valor actual en la página. No congelan la página porque se ejecutan en segundo plano con hilos separados.

Multi-threading: con múltiples iframes

Otra forma de lograr esto es usar múltiples iframes , cada uno ejecutará un hilo. Podemos darle al iframe algunos parámetros mediante la URL y el iframe puede comunicarse con su padre para obtener el resultado y volver a imprimirlo (el iframe debe estar en el mismo dominio).

¡Este ejemplo no funciona en todos los navegadores! iframes generalmente se ejecutan en el mismo subproceso / proceso que la página principal (pero Firefox y Chromium parecen manejarlo de manera diferente).

Como el fragmento de código no es compatible con varios archivos HTML, solo proporcionaré los diferentes códigos aquí:

index.html:

//The 3 iframes containing the code (take the thread id in param) <iframe id="threadFrame1" src="thread.html?id=1"></iframe> <iframe id="threadFrame2" src="thread.html?id=2"></iframe> <iframe id="threadFrame3" src="thread.html?id=3"></iframe> //Divs that shows the result <div id="result1"></div> <div id="result2"></div> <div id="result3"></div> <script> //This function is called by each iframe function threadResult(threadId, result) { document.getElementById("result" + threadId).innerHTML = result; } </script>

thread.html:

//Get the parameters in the URL: http://stackoverflow.com/a/1099670/2576706 function getQueryParams(paramName) { var qs = document.location.search.split(''+'').join('' ''); var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g; while (tokens = re.exec(qs)) { params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]); } return params[paramName]; } //The thread code (get the id from the URL, we can pass other parameters as needed) var MAX_VALUE = 100000; (function thread() { var threadId = getQueryParams(''id''); for(var i=0; i<MAX_VALUE; i++){ parent.threadResult(threadId, i); } })();

Simular multi-threading

Single-thread: emula la concurrencia de JavaScript con setTimeout ()

La forma ''ingenua'' sería ejecutar la función setTimeout() una después de la otra como esta:

setTimeout(function(){ /* Some tasks */ }, 0); setTimeout(function(){ /* Some tasks */ }, 0); [...]

Pero este método no funciona porque cada tarea se ejecutará una después de la otra.

Podemos simular la ejecución asincrónica llamando a la función recursivamente de esta manera:

var MAX_VALUE = 10000; function thread1(value, maxValue){ var me = this; document.getElementById("result1").innerHTML = value; value++; //Continue execution if(value<=maxValue) setTimeout(function () { me.thread1(value, maxValue); }, 0); } function thread2(value, maxValue){ var me = this; document.getElementById("result2").innerHTML = value; value++; if(value<=maxValue) setTimeout(function () { me.thread2(value, maxValue); }, 0); } function thread3(value, maxValue){ var me = this; document.getElementById("result3").innerHTML = value; value++; if(value<=maxValue) setTimeout(function () { me.thread3(value, maxValue); }, 0); } thread1(0, MAX_VALUE); thread2(0, MAX_VALUE); thread3(0, MAX_VALUE);

<div id="result1"></div> <div id="result2"></div> <div id="result3"></div>

Como puede ver, este segundo método es muy lento y congela el navegador porque usa el hilo principal para ejecutar las funciones.

Single-thread: emula la concurrencia de JavaScript con el rendimiento

Yield es una nueva característica en ECMAScript 6 , solo funciona en la versión más antigua de Firefox y Chrome (en Chrome necesitas habilitar el JavaScript experimental que aparece en chrome: // flags / # enable-javascript-harmony ).

La palabra clave yield hace que se detenga la ejecución de la función del generador y el valor de la expresión que sigue a la palabra clave yield se devuelve al llamador del generador. Se puede considerar como una versión basada en generador de la palabra clave return.

Un generador le permite suspender la ejecución de una función y reanudarla más tarde. Se puede usar un generador para programar sus funciones con una técnica llamada trampolining .

Aquí está el ejemplo:

var MAX_VALUE = 10000; Scheduler = { _tasks: [], add: function(func){ this._tasks.push(func); }, start: function(){ var tasks = this._tasks; var length = tasks.length; while(length>0){ for(var i=0; i<length; i++){ var res = tasks[i].next(); if(res.done){ tasks.splice(i, 1); length--; i--; } } } } } function* updateUI(threadID, maxValue) { var value = 0; while(value<=maxValue){ yield document.getElementById("result" + threadID).innerHTML = value; value++; } } Scheduler.add(updateUI(1, MAX_VALUE)); Scheduler.add(updateUI(2, MAX_VALUE)); Scheduler.add(updateUI(3, MAX_VALUE)); Scheduler.start()

<div id="result1"></div> <div id="result2"></div> <div id="result3"></div>

¿Hay alguna forma de hacer multi-threading en JavaScript?


¡Si no puedes o no quieres usar algo de AJAX, usa un iframe o diez! ;) Puede tener procesos ejecutándose en iframes en paralelo con la página maestra sin preocuparse por problemas comparables de navegador o problemas de sintaxis con dot net AJAX, etc., y puede llamar el JavaScript de la página maestra (incluido el JavaScript que ha importado) desde un iframe

Por ejemplo, en un iframe principal, para llamar a egFunction() en el documento principal una vez que el contenido del iframe se haya cargado (esa es la parte asincrónica)

parent.egFunction();

Genere dinámicamente los iframes también para que el código html principal esté libre de ellos si lo desea.


Aquí hay solo una manera de simular multi-threading en Javascript

Ahora voy a crear 3 hilos que calcularán números adicionales, los números se pueden dividir con 13 y los números se pueden dividir con 3 hasta 10000000000. Y estas 3 funciones no se pueden ejecutar al mismo tiempo que lo que significa Concurrencia. Pero les mostraré un truco que hará que estas funciones se ejecuten recursivamente al mismo tiempo: jsFiddle

Este código me pertenece

Parte del cuerpo

<div class="div1"> <input type="button" value="start/stop" onclick="_thread1.control ? _thread1.stop() : _thread1.start();" /><span>Counting summation of numbers till 10000000000</span> = <span id="1">0</span> </div> <div class="div2"> <input type="button" value="start/stop" onclick="_thread2.control ? _thread2.stop() : _thread2.start();" /><span>Counting numbers can be divided with 13 till 10000000000</span> = <span id="2">0</span> </div> <div class="div3"> <input type="button" value="start/stop" onclick="_thread3.control ? _thread3.stop() : _thread3.start();" /><span>Counting numbers can be divided with 3 till 10000000000</span> = <span id="3">0</span> </div>

Parte Javascript

var _thread1 = {//This is my thread as object control: false,//this is my control that will be used for start stop value: 0, //stores my result current: 0, //stores current number func: function () { //this is my func that will run if (this.control) { // checking for control to run if (this.current < 10000000000) { this.value += this.current; document.getElementById("1").innerHTML = this.value; this.current++; } } setTimeout(function () { // And here is the trick! setTimeout is a king that will help us simulate threading in javascript _thread1.func(); //You cannot use this.func() just try to call with your object name }, 0); }, start: function () { this.control = true; //start function }, stop: function () { this.control = false; //stop function }, init: function () { setTimeout(function () { _thread1.func(); // the first call of our thread }, 0) } }; var _thread2 = { control: false, value: 0, current: 0, func: function () { if (this.control) { if (this.current % 13 == 0) { this.value++; } this.current++; document.getElementById("2").innerHTML = this.value; } setTimeout(function () { _thread2.func(); }, 0); }, start: function () { this.control = true; }, stop: function () { this.control = false; }, init: function () { setTimeout(function () { _thread2.func(); }, 0) } }; var _thread3 = { control: false, value: 0, current: 0, func: function () { if (this.control) { if (this.current % 3 == 0) { this.value++; } this.current++; document.getElementById("3").innerHTML = this.value; } setTimeout(function () { _thread3.func(); }, 0); }, start: function () { this.control = true; }, stop: function () { this.control = false; }, init: function () { setTimeout(function () { _thread3.func(); }, 0) } }; _thread1.init(); _thread2.init(); _thread3.init();

Espero que de esta manera sea útil.


Con la specification HTML5 no necesita escribir demasiado JS para el mismo o encontrar algunos hacks.

Una de las características introducidas en HTML5 es Web Workers, que es JavaScript ejecutándose en segundo plano, independientemente de otros scripts, sin afectar el rendimiento de la página.

Es compatible con casi todos los navegadores:

Chrome - 4.0+

IE - 10.0+

Mozilla - 3.5+

Safari - 4.0+

Opera - 11.5+


Con las "especificaciones secundarias" de HTML5, ya no es necesario piratear javascript con setTimeout (), setInterval (), etc.

HTML5 & Friends presenta la especificación javascript Web Workers . Es una API para ejecutar scripts de forma asincrónica e independiente.

Enlaces a la specification y un tutorial .


Consulte http://caniuse.com/#search=worker para obtener la información de soporte más actualizada.

Lo siguiente fue el estado de apoyo alrededor de 2009.

Las palabras para las que desea buscar en google son subprocesos de trabajo de JavaScript

Además de Gears no hay nada disponible en este momento, pero se habla mucho acerca de cómo implementar esto, así que supongo que mire esta pregunta ya que la respuesta, sin duda, cambiará en el futuro.

Aquí está la documentación relevante para Gears: WorkerPool API

WHATWG tiene un Proyecto de Recomendación para los hilos de trabajo: Web Workers

Y también están los hilos de trabajo DOM de Mozilla

Actualización: junio de 2009, estado actual del soporte del navegador para hilos de JavaScript

Firefox 3.5 tiene trabajadores web. Algunas demostraciones de trabajadores web, si quieres verlos en acción:

El complemento de Gears también se puede instalar en Firefox.

Safari 4 y los Nightlies de WebKit tienen hilos de trabajo:

Chrome tiene Gears integrado, por lo que puede hacer subprocesos, aunque requiere un mensaje de confirmación del usuario (y utiliza una API diferente para los trabajadores de la web, aunque funcionará en cualquier navegador con el complemento Gears instalado):

  • Google Gears WorkerPool Demo (no es un buen ejemplo, ya que se ejecuta demasiado rápido para probarlo en Chrome y Firefox, aunque IE lo ejecuta lo suficientemente lento como para verlo bloqueando la interacción)

IE8 e IE9 solo pueden hacer hilos con el plugin Gears instalado



En JavaScript sin formato, lo mejor que puede hacer es usar las pocas llamadas asincrónicas (xmlhttprequest), pero eso no es realmente muy útil y muy limitado. Gears agrega varias API al navegador, algunas de las cuales se pueden usar para enhebrar el soporte.


Javascript no tiene hilos, pero sí tenemos trabajadores.

Los trabajadores pueden ser una buena opción si no necesita objetos compartidos.

La mayoría de las implementaciones de navegador distribuirán trabajadores en todos los núcleos permitiéndole utilizar todos los núcleos. Puedes ver una demostración de esto here .

Desarrollé una biblioteca llamada task.js que hace que esto sea muy fácil de hacer.

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

function blocking (exampleArgument) { // block thread } // turn blocking pure function into a worker task const blockingAsync = task.wrap(blocking); // run task on a autoscaling worker pool blockingAsync(''exampleArgumentValue'').then(result => { // do something with result });


No existe un verdadero multi-threading en Javascript, pero puede obtener un comportamiento asincrónico utilizando setTimeout() y las solicitudes asíncronas de AJAX.

¿Qué estás tratando de lograr exactamente?


No hay enhebrado verdadero en JavaScript. JavaScript siendo el lenguaje maleable que es, te permite emular un poco. Aquí hay un trampolining que encontré el otro día.


Otro posible método es usar un intérprete de JavaScript en el entorno de JavaScript.

Al crear múltiples intérpretes y controlar su ejecución desde el hilo principal, puede simular el multi-threading con cada subproceso ejecutándose en su propio entorno.

El enfoque es algo similar a los trabajadores de la web, pero le da acceso al intérprete al entorno global del navegador.

Hice un pequeño proyecto para demostrar esto .

Una explicación más detallada en esta publicación de blog .


Podría usar JavaScript narrativo , un compilador que transformará su código en una máquina de estados, lo que le permitirá emular el enhebrado. Lo hace al agregar un operador de "rendimiento" (anotado como ''->'') al lenguaje que le permite escribir código asíncrono en un único bloque de código lineal.