2010-04-07 17 views
7

Tengo una función de JavaScript que es bastante larga y realiza una serie de tareas, me gustaría informar el progreso al usuario actualizando el contenido de un elemento SPAN con un mensaje a medida que avanzo. Intenté agregar document.getElementById ('spnProgress'). InnerText = ... en todo el código de la función.¿Cómo informar el progreso de una función de JavaScript?

Sin embargo, mientras se ejecuta la función, la IU no se actualizará, por lo que solo verá el último mensaje escrito en el SPAN que no es de mucha ayuda.

Mi solución actual es dividir la tarea en una serie de funciones, al final de cada una configuro el mensaje SPAN y luego "dispare" el siguiente con una llamada a window.setTimeout con un retraso muy corto (por ejemplo 10 ms). Esto produce control y permite al navegador volver a pintar el SPAN con el mensaje actualizado antes de comenzar el siguiente paso.

Sin embargo, me parece muy complicado y difícil de seguir el código, estoy pensando que debe haber una mejor manera. ¿Alguien tiene alguna sugerencia? ¿Hay alguna manera de obligar al SPAN a volver a pintar sin tener que abandonar el contexto de la función?

Gracias

Respuesta

7

La forma en que lo está haciendo es el camino correcto (por el momento, esto puede cambiar a medida que surgen y normas se adoptan [ver Andrew Aylett de answer], pero no por un tiempo todavía). Debes ceder así para permitir que el navegador haga sus actualizaciones de UI. Descubrí que cuanto más pienso así, más limpias son las cosas, pero las primeras puñaladas que hice al respecto fueron bastante "desordenadas". Espero que encuentres lo mismo a medida que te acostumbras.

+0

Esta es la elección correcta. – Kangkan

0

Eso es como preguntar si es posible interrumpir un procedimiento sin interrumpir un procedimiento. La respuesta es no. Debes usar setTimeout() o setInterval() para pasar el control al motor de renderizado del navegador.

Si usa setInterval() puede ejecutar ese proceso y en su función de ejecución simplemente actualice una variable externa, que será consultada por la función llamada por setInterval(). De esta forma, solo tiene que hacer una llamada en lugar de hacerlas en un bucle.

0

No es que yo sepa. Se podría romper su código de tal manera que las funciones individuales pueden compartir las variables, por lo tanto:

var a = some_local_state(); 
runTasksWithProgress([ 
    function() { 
     do_some_work(a); 
     a = a + 1; 
    }, 
    function() { 
     do_some_other_work(a); 
     a = a * 2; 
    }, 
    ... 
    ]); 

runTasksWithProgress es un poco complicado. Básicamente invocaría la primera tarea, actualizaría el estado y luego configuraría una devolución de llamada para ejecutar tareas posteriores.

Este enfoque podría aliviar parte del dolor.

2

Debe tener en cuenta que en determinados navegadores, recibirá un mensaje de tiempo de espera de script si tiene un script de ejecución larga. Entonces es realmente deseable dividir esto usando un temporizador.

Habiendo dicho esto, si está buscando una forma realmente estructurada de hacer esto, entonces puede ver una biblioteca de tareas en segundo plano que escribí para un proyecto de revisión ortográfica. Le permite implementar map/reduce contra matrices de datos en un temporizador.

https://github.com/jameswestgate/taskjs

+0

+1 buen punto sobre el tiempo de espera del script. –

0

Algo como esto puede funcionar si el trabajo de su función se realiza en un bucle. Comprueba la cantidad de tiempo que ha pasado y actualiza la barra de progreso si ha pasado 1/2 segundo. (El ejemplo no está probado. Por lo tanto, es posible que deba jugar un poco con él.)

var start; 
function longRunning(lastState){ 
    start = (new Date); 
    for(var i = lastState; i < 1e6 /*= 1000000 iterations */; ++i){ 
     if((new Date)-start<500){ 
      // do your stuff; 
     } 
     else{ 
      // call a function to update the progress bar 
      updateProgressBar(); 
      // continue the loop... 
      setTimeout(function(){longRunning(i);},13); 
      break; 
     } 
    } 

} 
longRunning(0); 
3

Si usted tiene el control del navegador de destino, es posible que pueda utilizar un HTML5 worker thread para hacer el trabajo en el fondo.

Cuestiones relacionadas