Tengo una tarea intensiva de CPU que necesito ejecutar en el cliente. Idealmente, me gustaría poder invocar la función y desencadenar eventos de progreso utilizando jquery para poder actualizar la interfaz de usuario.

Sé que JavaScript no admite subprocesos, pero he visto algunos artículos prometedores que intentan imitar subprocesos utilizando setTimeout.

¿Cuál es el mejor enfoque para esto? Gracias.

46
Rob 21 jul. 2009 a las 19:57

9 respuestas

La mejor respuesta

Tuve un problema similar que resolver recientemente donde necesitaba mantener mi hilo de interfaz de usuario libre mientras procesaba algunos datos para mostrar.

Escribí una biblioteca Background.js para manejar algunos escenarios: una cola de fondo secuencial (basada en la biblioteca WorkerQueue), una lista de trabajos donde cada uno se llama en cada temporizador y un iterador de matriz para ayudar a dividir su trabajo en trozos más pequeños . Ejemplos y código aquí: https://github.com/kmalakoff/background

¡Disfrutar!

19
Kevin 29 ago. 2011 a las 11:36

Mi recomendación más fuerte es mostrar un simple loading.gif durante la operación. El usuario a menudo acepta algo de duración si se le ha "dicho" que podría llevar algún tiempo.

Ajaxload - Ajax cargando generador de gif

0
dbd 21 jul. 2009 a las 16:06

Dependiendo de cuáles sean sus requisitos, puede bajar fácilmente usando Gears. Gears admite hilos, que podrían hacer lo que quieras.

Como mencionó, setTimeout es la otra opción. Dependiendo del tipo de su tarea, puede pasar cada iteración de un ciclo a una llamada setTimeout separada con un poco de espacio intermedio, o puede necesitar separar partes de su algoritmo principal en funciones separadas que se pueden llamar una por una en de la misma manera que llamarías a cada iteración.

4
Jani Hartikainen 21 jul. 2009 a las 16:05

Este es un ejemplo muy básico de cómo crear hilos en JavaScript. Tenga en cuenta que depende de usted interrumpir las funciones de su hilo (instrucción de rendimiento). Si lo desea, puede usar un setTimeout en lugar de mi bucle while para ejecutar el programador periódicamente. Tenga en cuenta también que este ejemplo solo funciona con JavaScript versión 1.7+ (firefox 3+) puedes probarlo aquí: http://jslibs.googlecode.com/svn/trunk/ jseval.html

//// thread definition
function Thread( name ) {

    for ( var i = 0; i < 5; i++ ) {

        Print(i+' ('+name+')');
        yield;
    }
}

//// thread management
var threads = [];

// thread creation
threads.push( new Thread('foo') );
threads.push( new Thread('bar') );

// scheduler
while (threads.length) {

    var thread = threads.shift();
    try {
        thread.next();
        threads.push(thread);
    } catch(ex if ex instanceof StopIteration) { }
}

La salida es:

0 (foo) 0 (bar) 1 (foo) 1 (bar) 2 (foo) 2 (bar) 3 (foo) 3 (bar) 4 (foo) 4 (bar) 
1
Franck Freiburger 21 jul. 2009 a las 16:53

Básicamente, lo que quiere hacer es dividir la operación en partes. Digamos que tiene 10 000 elementos que desea procesar, guárdelos en una lista y luego procese un pequeño número de ellos con un pequeño retraso entre cada llamada. Aquí hay una estructura simple que podría usar:

function performTask(items, numToProcess, processItem) {
    var pos = 0;
    // This is run once for every numToProcess items.
    function iteration() {
        // Calculate last position.
        var j = Math.min(pos + numToProcess, items.length);
        // Start at current position and loop to last position.
        for (var i = pos; i < j; i++) {
            processItem(items, i);
        }
        // Increment current position.
        pos += numToProcess;
        // Only continue if there are more items to process.
        if (pos < items.length)
            setTimeout(iteration, 10); // Wait 10 ms to let the UI update.
    }
    iteration();
}

performTask(
    // A set of items.
    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'],
    // Process two items every iteration.
    2,
    // Function that will do stuff to the items. Called once for every item. Gets
    // the array with items and the index of the current item (to prevent copying
    // values around which is unnecessary.)
    function (items, index) {
        // Do stuff with items[index]
        // This could also be inline in iteration for better performance.
    });

También tenga en cuenta que Google Gears tiene soporte para trabajar en un hilo separado. Firefox 3.5 también presentó sus propios trabajadores que hacen lo mismo (aunque siguen a el estándar W3, mientras que Google Gears utiliza sus propios métodos).

38
Blixt 21 jul. 2009 a las 16:28

Gran respuesta Kevin! Escribí algo similar hace unos años, aunque menos sofisticado. El código fuente está aquí si alguien lo quiere:

http://www.leapbeyond.com/ric/jsUtils/TaskQueue.js

Cualquier cosa con un método run() se puede poner en cola como una tarea. Las tareas pueden volver a ponerse en cola para realizar trabajos en fragmentos. Puede priorizar tareas, agregarlas / eliminarlas a voluntad, pausar / reanudar toda la cola, etc. Funciona bien con operaciones asincrónicas; mi uso original para esto fue administrar varias solicitudes XMLHttpRequests simultáneas.

El uso básico es bastante simple:

var taskQueue = new TaskQueue();
taskQueue.schedule("alert('hello there')");

Los comentarios del encabezado en el archivo .js proporcionan ejemplos más avanzados.

2
rkagerer 6 nov. 2012 a las 18:36

Si puede forzar el uso del navegador, o si ya sabe que es una nueva versión de Firefox, puede usar el nuevo Trabajadores web de Mozilla. Le permite generar nuevos hilos.

9
Sinan Taifour 21 jul. 2009 a las 16:59

Aquí está mi solución al problema, en caso de que alguien quiera una pieza de código simple que se pueda copiar y pegar:

    var iterate = function (from, to, action, complete) {
        var i = from;
        var impl = function () {
            action(i);
            i++;
            if (i < to) setTimeout(impl, 1);
            else complete();
        };
        impl();
    };
2
ironic 21 may. 2014 a las 09:26

Parece que este problema se ha resuelto en el nodo mismo.
requiere child_process que se incluye en nodejs 0.10.4

-1
wonea 6 dic. 2016 a las 11:26