2011-08-09 15 views
11

Así que tengo un objeto JSON grande que estoy volviendo del servidor, luego construyendo una datatable desde él y mostrándolo en el formulario. Esto generalmente toma unos segundos ... así que estaba pensando en una barra de carga. Tengo la lógica detrás de la barra de carga, sin embargo, el ciclo que crea los datos hmtl bloquea el navegador y no puedo llamar al elemento que necesito actualizar.Cómo hacer Threading en Javascript

Aquí es mi función para hacer esto:

function buildDataTable(db_table, container_id) { 
    var $pb = $("<div id=\"progress-bar\"></div>"); 
    $(container_id).html($pb); 
    $pb.progressbar({ 
     value: 0 
    }); 
    $.post("post location", { 
     view: "all" 
    }, function (data) { 
     var headers = ""; 
     var contents = ""; 
     var jsonObject = $.parseJSON(data); 
     var tik = Math.round(jsonObject.length/100); 
    for (key in jsonObject[0]) { 
      headers += "<th>" + key.replace(" ", "&nbsp;") + "</th>"; 
     } 
     for (i in jsonObject) { 
      contents += "<tr>"; 
      for (j in jsonObject[i]) { 
       contents += "<td class=\"border-right\">" + jsonObject[i][j] + "</td>"; 
      } 
      contents += "</tr>"; 
      if(Math.round(i/tik) == i/tik) { 
/* if I run the alert (between popups) i can see the progressbar update, otherwise I see no update, the progressbar appears empty then the $(container_id) element is updated with the table i've generated */ 
       alert(''); 
       $pb.progressbar("value",i/tik); 
      } 
     } 
     var html = "<table cellpadding=\"5\" cellspacing=\"0\"><thead><tr>" + headers + "</tr></thead><tbody>" + contents + "</tbody></table>"; 

     $(container_id).html(html); 
     $(container_id).children("table:first").dataTable({ 
      "bJQueryUI": true, 
      "sScrollX": "100%" 
     }); 
    }); 
} 
+1

JavaScript tiene un solo subproceso. Tendrá que dividir su trabajo en pedazos y llamarlos en secuencia usando "setTimeout" para permitir que la GUI se actualice durante el procesamiento, pero aun así el navegador aún parecerá poco receptivo. – maerics

+0

Entonces, ¿es mejor simplemente usar un gif animado y no mostrar el progreso real? – rlemon

+0

@maerics: Pensé que las solicitudes asíncronas abrían un nuevo hilo? – Anthony

Respuesta

19

[Agregado mi comentario como respuesta]

JavaScript es de un solo subproceso. Tendrá que dividir su trabajo en pedazos y llamarlos en secuencia usando "setTimeout" para permitir que la GUI se actualice durante el procesamiento (entre sus llamadas) pero aun así el navegador aún no parecerá responder.

+2

En realidad, los [trabajadores web] (http://www.whatwg.org/specs/web-apps/current-work/complete/workers.html) ofrecen una buena alternativa a la solución 'setTimeout' ... – revers

+0

@revers: sí, WebWorkers parece haber sido diseñado para exactamente este tipo de problema; sin embargo, es un borrador de HTML5 (la última vez que lo verifiqué), por lo que los navegadores más nuevos tendrán cierto soporte, pero habrá diferencias de comportamiento. Los navegadores antiguos tendrán que hacer algo pesado como sugerí. – maerics

+0

Sí, tienes razón. Parece que IE no lo admitirá antes de la versión 10 ... – revers

3

Usted puede intentar usar WebWorker: https://developer.mozilla.org/en/DOM/Worker
Así trabajador se ejecutan en paralelo del hilo principal, no se puede lograr exactamente multi-threading usando trabajadores: no se puede modificar la interfaz de usuario de un trabajador.
Quizás pueda crear su cuadrícula como una cadena en un trabajador y cuando el trabajador termine, agréguela donde desee.

+0

Parece que su HTTP Secure está teniendo problemas ... no puede cargar ninguna de las páginas en https – rlemon

+0

También puede ver [en esta página] (http://www.html5rocks.com/en/tutorials/workers/ conceptos básicos/# toc-enviornment-subworkers) a continuación. Pero como menciona maerics, los trabajadores de la Web son bastante nuevos y solo cuentan con el respaldo de navegadores nuevos. – revers

2

Si hace todo el edificio de la base de datos en un setTimeout, el resto de la página debe responder.

Puede construir los elementos html en esa función, y cuando esté listo, adjúntelo al DOM. También deberá llamar a funciones o enviar eventos para actualizar la visualización de la barra de progreso.

Edición después de comentario:

Esto ejecutará en segundo plano y no afectará a la capacidad de respuesta de la página:

window.setTimeout(function() {buildDataTable(db_table, container_id)}, 0);

Ya actualice su progressbar de su función, así que esto debería hazlo.

Sin embargo, es posible que desee desacoplar el código que genera la tabla de datos del código actualizando la barra de progreso.

+0

¿Puedes decir esto? ajustar la llamada a la función en setTimeout (function() {** Function Call **}, 0); – rlemon

+0

Si buildDataTable es una tarea de larga duración (y OP dice que sí), este enfoque no resolverá el problema de la IU que no responde, ya que se bloqueará mientras se está ejecutando (podría permitir otra cosa justo antes de que comience a ejecutarse). Tendría que dividir la tarea en fragmentos más pequeños y llamar a setTimeout para cada uno de estos para obtener algún tipo de tiempo compartido. – UpTheCreek

0

Parece que la única manera limpia de hacerlo en mi aplicación es procesar el json en el servidor y crear el html allí. Luego devuelva el html al navegador a través de $.post()

Se perderá la barra de progreso. sin embargo, puedo usar un gif infinito de carga ...