Pregunta

¿Hay alguna forma de realizar subprocesos múltiples en JavaScript?

¿Fue útil?

Solución

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

El siguiente fue el estado del apoyo alrededor de 2009.


Las palabras que quieres buscar en Google son Hilos de trabajo de JavaScript

Aparte de Engranajes No hay nada disponible en este momento, pero se habla mucho sobre cómo implementar esto, así que supongo que observe esta pregunta ya que la respuesta sin duda cambiará en el futuro.

Aquí está la documentación relevante para Gears: API de grupo de trabajadores

WHATWG tiene un borrador de recomendación para subprocesos de trabajo: Trabajadores web

Y también está el de Mozilla. Hilos de trabajadores DOM


Actualizar: Junio ​​de 2009, estado actual de la compatibilidad del navegador con subprocesos de JavaScript

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

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

Safari 4, y el Noches WebKit tener hilos de trabajo:

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

  • Demostración de Google Gears WorkerPool (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 ver que bloquea la interacción)

IE8 y IE9 Sólo puedo hacer hilos con el complemento Gears instalado.

Otros consejos

Forma diferente de realizar subprocesos múltiples y asincrónicos en JavaScript

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

Había alguna forma ingeniosa de simular una ejecución asincrónica con Producir, setTimeout(), setInterval(), XMLHttpRequest o controladores de eventos (consulte el final de esta publicación para ver un ejemplo con producir y setTimeout()).

Pero con HTML5 ahora podemos usar Worker Threads para paralelizar la ejecución de funciones.A continuación se muestra un ejemplo de uso.


Subprocesos múltiples reales

Subprocesos múltiples:Hilos de trabajo de JavaScript

HTML5 introdujo los hilos de trabajo web (consulte: compatibilidades de navegadores)
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 más información sobre trabajador web lee la documentación o este tutorial.

Aquí hay un ejemplo simple con 3 subprocesos de Web Worker que cuentan hasta MAX_VALUE y muestran el valor calculado actual 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 subprocesos se ejecutan al mismo tiempo e imprimen su valor actual en la página.No congelan la página porque se ejecutan en segundo plano con subprocesos separados.


Subprocesos múltiples:con múltiples iframes

Otra forma de lograr esto es utilizar múltiples marcos flotantes, cada uno ejecutará un hilo.podemos dar la marco flotante algunos parámetros por la URL y el marco flotante puede comunicarse con sus padres para obtener el resultado e imprimirlo de nuevo (el marco flotante debe estar en el mismo dominio).

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

Dado que el fragmento de código no admite varios archivos HTML, aquí solo proporcionaré los diferentes códigos:

índice.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>

hilo.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 subprocesos múltiples

Hilo único:emular la concurrencia de JavaScript con setTimeout()

La forma 'ingenua' sería ejecutar la función. setTimeout() uno tras otro así:

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

Pero este método No funciona porque cada tarea se ejecutará una tras otra.

Podemos simular una ejecución asincrónica llamando a la función de forma recursiva así:

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 utiliza el hilo principal para ejecutar las funciones.


Hilo único:emular la concurrencia de JavaScript con rendimiento

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

La palabra clave de rendimiento hace que la ejecución de la función del generador se detenga y el valor de la expresión que sigue a la palabra clave de rendimiento se devuelve a la persona que llama 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 utilizar un generador para programar sus funciones con una técnica llamada trampolín.

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>

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

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

Enlaces a la especificación y un tutorial.

No existe un verdadero subprocesamiento en JavaScript.JavaScript, siendo el lenguaje maleable que es, le permite emular parte de él.Aquí hay un ejemplo Me encontré el otro día.

No existe un verdadero subproceso múltiple en Javascript, pero puede obtener un comportamiento asincrónico usando setTimeout() y solicitudes AJAX asincrónicas.

¿Qué estás tratando de lograr exactamente?

Aquí hay sólo una manera de simular subprocesos múltiples en Javascript

Ahora voy a crear 3 hilos que calcularán la suma de números, los números se pueden dividir por 13 y los números se pueden dividir por 3 hasta 10000000000.Y estas 3 funciones no pueden ejecutarse al mismo tiempo que lo que significa concurrencia.Pero te 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 de 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 esta manera sea útil.

Podrías usar JavaScript narrativo, un compilador que transformará su código en una máquina de estados, permitiéndole efectivamente emular subprocesos.Lo hace agregando un operador "cedente" (anotado como '->') al lenguaje que le permite escribir código asincrónico en un único bloque de código lineal.

El nuevo motor v8 que debería salir hoy lo soporta (creo)

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

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

El enfoque es algo similar al de los trabajadores web, pero usted le da al intérprete acceso 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.

En Javascript sin formato, lo mejor que puede hacer es utilizar algunas llamadas asincrónicas (xmlhttprequest), pero eso no es realmente un subprocesamiento y es muy limitado. engranajes de google agrega una serie de API al navegador, algunas de las cuales se pueden usar para admitir subprocesos.

Si no puedes o no quieres usar ningún elemento 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 entre navegadores o problemas de sintaxis con dot net AJAX, etc., y puede llamar al JavaScript de la página maestra (incluido el JavaScript que ha importado) desde un marco flotante.

Por ejemplo, en un iframe principal, para llamar egFunction() en el documento principal una vez que se haya cargado el contenido del iframe (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.

Javascript no tiene hilos, pero sí tenemos trabajadores.

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

La mayoría de las implementaciones de navegadores distribuirán los trabajadores entre todos los núcleos, lo que le permitirá utilizar todos los núcleos.Puedes ver una demostración de esto. aquí.

He desarrollado una biblioteca llamada tarea.js eso hace que esto sea muy fácil de hacer.

tarea.js Interfaz simplificada para ejecutar código con uso intensivo de CPU 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
});

Con HTML5 especificación No es necesario escribir demasiado JS para lo mismo ni encontrar algunos trucos.

Una de las características introducidas en HTML5 es Trabajadores web 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:

Cromo - 4.0+

Es decir, 10.0+

Mozilla - 3.5+

Safari - 4.0+

Ópera - 11.5+

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top