2008-10-17 15 views
21

He leído la publicación here sobre el uso de setTimeout() durante el procesamiento intensivo de DOM (con JavaScript), pero ¿cómo puedo integrar esta función con el código siguiente? El siguiente código funciona bien para un número pequeño de opciones, pero cuando el número de opciones aumenta demasiado, mi GIF animado "por favor espere" se congela mientras se procesa el JavaScript local. ¡Gracias!¿Cómo puedo devolver el control (brevemente) al navegador durante el procesamiento intensivo de JavaScript?

function appendToSelect() { 
    $("#mySelect").children().remove() ; 
    $("#mySelect").html(
     '<option selected value="' + obj.data[0].value + '">' 
     + obj.data[0].name 
     + '</option>' 
    ); 
    var j = 1 ; 
    for (var i = 1; i < obj.data.length; i++) { 
     $("#mySelect").append(
      '<option value="' + obj.data[i].value + '">' 
      + obj.data[i].name 
      + '</option>' 
     ); 
    } 
} 
+2

dígales que usen Chrome y tendrán JITted javascript :) –

Respuesta

28

Aquí es una solución:

function appendToSelect() { 
    $("#mySelect").children().remove(); 
    $("#mySelect").html(
    '<option selected value="'+obj.data[0].value+'">' 
    + obj.data[0].name 
    + '</option>' 
); 
    obj.data.splice(0, 1); // we only want remaining data 
    var appendOptions = function() { 
    var dataChunk = obj.data.splice(0, 10); // configure this last number (the size of the 'chunk') to suit your needs 
    for(var i = 0; i < dataChunk.length; i++) { 
     $("#mySelect").append(
     '<option value="' + dataChunk[i].value + '">' 
     + dataChunk[i].name 
     + '</option>' 
    ); 
    } 
    if(obj.data.length > 0) { 
     setTimeout(appendOptions, 100); // change time to suit needs 
    } 
    }; 
    appendOptions(); // kicks it off 
} 

No es tan elegante como @Borgar's solución, pero se entiende la idea. Básicamente, estoy haciendo lo mismo, pero todo en tu función en vez de dividirla en una función de orden superior como lo hace él. Me gusta su solución, pero si no lo hace, quizás esto funcione para usted.


EDIT: Para aquellos que no ven inmediatamente, una de las principales diferencias entre esta solución y @Borgar's es que esta solución le permite establecer el tamaño de los 'trozos' de datos que se procesan entre cada tiempo de espera. @Borgar's tiempo de espera después de cada miembro de la matriz se procesa. Si tengo tiempo, intentaré crear una función de orden superior para manejar esto, de modo que sea más elegante. ¡Sin promesas! ;)


EDIT: Por lo tanto, aquí está mi adaptación de la solución @Borgar's, lo que permite establecer un tamaño 'trozo' y configurar el valor de tiempo de espera más fácilmente:

function incrementallyProcess(workerCallback, data, chunkSize, timeout, completionCallback) { 
    var itemIndex = 0; 
    (function() { 
    var remainingDataLength = (data.length - itemIndex); 
    var currentChunkSize = (remainingDataLength >= chunkSize) ? chunkSize : remainingDataLength; 
    if(itemIndex < data.length) { 
     while(currentChunkSize--) { 
     workerCallback(data[itemIndex++]); 
     } 
     setTimeout(arguments.callee, timeout); 
    } else if(completionCallback) { 
     completionCallback(); 
    } 
    })(); 
} 

function appendToSelect() { 
    $("#mySelect").children().remove(); 
    $("#mySelect").html(
    '<option selected value="' + obj.data[0].value + '">' 
    + obj.data[0].name 
    + '</option>' 
); 
    obj.data.splice(0,1); // we only want remaining data  
    incrementallyProcess(function(data) { 
    $("#mySelect").append(
    '<option value="' + data.value + '">' 
    + data.name 
    + '</option>' 
    ); 
    }, obj.data, 10, 100, removeAnimatedGifFunction); // last function not required... 
} 

la esperanza de que me ayuda - Creo que esto combina lo mejor de ambas soluciones. Aviso, la segunda función anónima ya no usa el valor del índice, sino que simplemente pasa el objeto completo (con el valor y las propiedades del nombre); eso lo hace un poco más limpio, ya que el índice del objeto actual realmente no es generalmente que es útil cuando se itera sobre cosas, IMO.

Estoy seguro de que todavía hay cosas que se podrían hacer para mejorar esto, pero eso queda como un ejercicio para el lector. ;)

-1

Usted tendría que volver a escribir la función de caché de la lista de elementos, a continuación, un bucle sobre la lista utilizando un contador de algún tipo.

Luego cuando el contador alcanza el contador% max_num_fore_esperanza == 0, vuelva a llamar al tiempo de espera a la función.

Asegúrese de borrar el caché y el contador al final de la lista completa, o utilice una función secundaria con un parámetro de conteo adicional.

20

Ocurre que estaba publicando sobre esto hace un momento here. Aquí es una función de bucle temporizado:

function processLoop(actionFunc, numTimes, doneFunc) { 
    var i = 0; 
    var f = function() { 
    if (i < numTimes) { 
     actionFunc(i++); // closure on i 
     setTimeout(f, 10) 
    } 
    else if (doneFunc) { 
     doneFunc(); 
    } 
    }; 
    f(); 
} 

Por su situación esto podría ser utilizado como esto:

function appendToSelect() { 

    $("#mySelect").children().remove() ; 
    $("#mySelect").html(
     '<option selected value="' + obj.data[0].value + '">' 
     + obj.data[0].name 
     + '</option>' 
); 
    var j = 1 ; 

    processLoop(function (i){ 
    $("#mySelect").append(
     '<option value="' + obj.data[i].value + '">' 
     + obj.data[i].name 
     + '</option>' 
    ); 
    }, obj.data.length); 

} 

Usted querrá asegurarse de que tiene un cierre o algún otro acceso al obj variable dentro de la función de iteración.

Espero que esto ayude.

4

Si necesita algo más simple, escribí un complemento jQuery para facilitar la escritura de bucles asincrónicos: jQuery Async.

Usando el plugin, su código puede reescribirse como:

function appendToSelect() { 
    $("#mySelect").children().remove() ; 
    $("#mySelect").html(
     '<option selected value="' + obj.data[0].value + '">' 
     + obj.data[0].name 
     + '</option>' 
    ); 

    ///////////////////////////// 
    var i = 1; 
    $.whileAsync({ 
     test: function(){ i < obj.data.length; } 
     loop: function() 
     { 
      $("#mySelect").append(
       '<option value="' + obj.data[i].value + '">' 
       + obj.data[i].name 
       + '</option>' 
      ); 
      i++; 
     } 
    }); 
    ///////////////////////////// 
} 

debería ayudar a la capacidad de respuesta. Ajuste la opción 'bulk' y 'delay' para obtener más control.

Cuestiones relacionadas