2010-10-20 5 views
5

J'ai récemment commencé à travailler avec jQuery et j'ai remarqué aujourd'hui un problème étrange avec son comportement. Si je comprends bien, JavaScript est un thread unique. Donc toutes ses opérations devraient fonctionner en FIFO. Cependant, cela ne semblait pas être le cas pour moi. S'il vous plaît considérer ce qui suit.jN'exécutant pas dans le bon ordre?

SETUP est la suivante

HTML:

3 divs

  • div # 1 => contient des éléments d'en-tête qui peut être cliqué pour exécuter la fonction de tri

  • div # 2 => contient les données à trier

  • div # 3 => contient un .gif de base qui est utilisé pour avertir l'utilisateur que certaines opérations est en cours d'exécution

jQuery - contient la fonction de tri qui fait la manipulation du DOM. Fondamentalement, il lit les données de la page HTML, stocke dans un tableau 2D et trie le tableau. Il efface ensuite div # 2 (div de données) et le reconstruit, en utilisant les données du tableau trié.

EXECUTION devait être comme suit

  • utilisateur clique sur l'un des en-têtes pour déclencher la fonction de tri
  • fonction de tri cache div # 2 et montre div # 3
  • fonction de tri est exécuté
  • une fois le tri terminé, div # 2 (données div) est affiché et div # 3 est caché

Cependant, voici ce qui semble se produire

  • les en-têtes

    utilisateur clique

  • genre se produit

  • masquage et d'affichage divs passe à la dernière étape

Initialement, comme je n'étais pas capable de voir les divs affichées/masquées, j'ai supposé que cela se passait trop vite pour que je le remarque. J'ai donc ajouté un délai aux fonctions .show() et .hide() de jQuery. Une fois cela fait, il était tout à fait évident que les actions de show et de hide étaient faites à la toute fin.

* SOLUTION * Après de longues recherches, j'ai réussi à obtenir ce travail comme je m'y attendais en utilisant des fonctions jQuery .queue() et .dequeue(). Le talon d'Achille ici était que je devais insérer un délai de 1 milliseconde entre chaque opération. Alors et seulement alors, le navigateur a pu cacher/montrer des divs comme je le voulais.Ainsi, les opérations se sont quelque chose comme ceci:

var theQueue = $({}); // jQuery on an empty object 

theQueue.queue("testQueue", 
       function(next) { 
        $("#loadingIndicator").show(); 
        $("#cases").hide(); 
        next(); 
       } 
      ); 
theQueue.delay(1, "testQueue"); 

theQueue.queue("testQueue", 
       function(next) { 
        doSort(columnNumber); //SORT 
        next(); 
       } 
      ); 
theQueue.delay(1, "testQueue"); 

theQueue.queue("testQueue", 
       function(next) { 
        $("#loadingIndicator").hide(); 
        $("#cases").show(); 
        next(); 
       } 
      ); 

theQueue.dequeue("testQueue"); 

}

Je ne suis certainement pas un expert en la matière, mais je pense que les opérations devraient être exécuter dans le même ordre comme on les appelle. Le navigateur n'est pas rendu dans le bon ordre? Est-ce que jQuery change l'ordre des opérations pour rendre les choses plus efficaces?

Alors que la «solution» fait le travail, je ne suis pas convaincu que c'est la meilleure solution dans ce scénario. Y a-t-un autre moyen de faire ça? Si nécessaire, je peux fournir des exemples de code de travail qui illustreront le problème. Je vous remercie. Sur une autre note, j'ai remarqué avec de grands ensembles de données, lorsque l'utilisateur clique sur un élément d'en-tête pour déclencher le tri, le navigateur ne répond plus. Je réalise qu'il exécute la fonction de tri, mais j'espérais qu'il y aurait un moyen d'éviter cela. Des pensées?

Répondre

7

Les opérations sont exécutées dans le même ordre que celui auquel elles sont appelées, mais le problème est que les éléments DOM et ce qui est affiché à l'écran sont deux choses distinctes. Le processus qui restitue les éléments à l'écran s'exécute dans le même environnement à thread unique que le code Javascript, de sorte qu'il ne peut afficher aucune modification sur le scénario tant que votre script n'est pas terminé. Pour que les modifications s'affichent, vous devez terminer votre script, puis le reprendre une fois que le moteur de rendu a eu la possibilité d'afficher les modifications.

Vous pouvez utiliser la méthode setTimeout pour rendre le contrôle du navigateur, et obtenir le reste du code pour commencer le plus tôt possible:

$("#loadingIndicator").show(); 
$("#cases").hide(); 

window.setTimeout(function(){ 

    doSort(columnNumber); //SORT 
    $("#loadingIndicator").hide(); 
    $("#cases").show(); 

}, 0); 
+0

Génial, merci pour l'explication facile à suivre. J'utilise maintenant cette méthode et je dois dire qu'elle utilise un peu moins de code que l'autre méthode que j'utilisais. À votre santé. – Harinder

1

.show() et .hide() sont membres de la file d'attente de fx, qui est exécuté de manière asynchrone, sans interrompre l'exécution du programme.

Les effets peuvent être mis en file d'attente séquentiellement par chaînage, mais un autre code s'exécutera indépendamment de l'exécution de la file d'attente fx. La façon d'obtenir l'ordre des opérations comme vous le souhaitez est de créer une file d'attente personnalisée comme vous l'avez fait, ou d'utiliser les fonctions de rappel pour chaque effet.

Par ex

$('#loadingIndicator').show(250,function(){ 
    $('#cases').hide(250,function(){ 
     doSort(columnNumber); 
    }).show(250, function(){ 
     $('#loadingIndicator').hide(250);}) 
}); 

JSFiddle example

ED: Je accidentellement le mot entier.

+0

Merci pour la perspicacité. Je suis sûr que cette information de file d'attente personnalisée sera utile dans un proche avenir. – Harinder

Questions connexes