Maison  >  Article  >  interface Web  >  Problème de blocage du thread de l'interface utilisateur causé par la synchronisation Jquery ajax blocking_jquery

Problème de blocage du thread de l'interface utilisateur causé par la synchronisation Jquery ajax blocking_jquery

WBOY
WBOYoriginal
2016-05-16 15:31:381487parcourir

En travaillant récemment sur un projet, j'ai rencontré un problème de blocage des threads de l'interface utilisateur causé par l'ajax synchronisé. Permettez-moi de partager avec vous mon processus de résolution de problèmes.

La raison est la suivante, car il existe plusieurs actions de requête asynchrones similaires sur la page Afin d'améliorer la réutilisabilité du code, j'ai encapsulé une fonction appelée getData, qui reçoit différents paramètres et est uniquement responsable de l'obtention des données. puis renvoyez les données. La logique de base supprimée est la suivante :

function getData1(){
    var result;
    $.ajax({
      url : "p.php",
      async : false,
      success: function(data){
        result = data;
      }
    });

  return result;
} 

L'ajax ici ne peut pas être asynchrone, sinon lorsque la fonction revient, le résultat n'a pas reçu de valeur et une erreur se produira. J'ai donc ajouté async:false. Il ne semble y avoir aucun problème. Je peux obtenir les données normalement en appelant cette fonction.

$(".btn1").click(function(){
    var data = getData1();
    alert(data);
});

Ensuite, je souhaite ajouter une autre fonction. Comme la requête ajax prend du temps, je dois avoir un effet de chargement sur la page avant d'envoyer la requête, c'est-à-dire afficher une image gif de "chargement" je pense que tout le monde. je l'ai également vu. Donc ma fonction de traitement devient comme ceci :

$(".btn1").click(function(){
    $(".loadingicon").show();
    var data = getData1();
    $(".loadingicon").hide();
    alert(data);
});

Affichez l'image de chargement avant de demander et masquez-la une fois la demande terminée. Il ne semble y avoir aucun problème. Afin de voir clairement l'effet, mon code p.php se met en veille pendant 3 secondes, comme suit :

<&#63;php
sleep(3);
echo ("aaaaaa");
&#63;>

Mais un problème est survenu lorsque je l'ai exécuté. Lorsque j'ai cliqué sur le bouton, l'image de chargement n'est pas apparue comme prévu et la page n'a pas répondu du tout. Après un long dépannage, j'ai trouvé la raison, qui est async:false.

Le thread de rendu (UI) du navigateur et le thread js s'excluent mutuellement lors de l'exécution d'opérations fastidieuses en js, le rendu des pages sera bloqué. Il n'y a aucun problème lorsque nous exécutons un ajax asynchrone, mais lorsqu'il est défini sur une requête synchrone, les autres actions (le code derrière la fonction ajax et le thread de rendu) s'arrêteront. Même si mon instruction d'opération DOM est la phrase précédant le lancement de la requête, cette requête de synchronisation bloquera "rapidement" le thread de l'interface utilisateur sans lui laisser le temps de s'exécuter. C'est pourquoi le code échoue.

setTimeout résout le problème de blocage

Maintenant que nous comprenons quel est le problème, trouvons une solution. Afin d'empêcher la requête ajax synchrone de bloquer le thread, j'ai pensé à setTimeout, mis le code de la requête dans sestTimeout et laissé le navigateur redémarrer un thread pour fonctionner. Le problème ne serait-il pas résolu ? Depuis, mon code est devenu comme ça :

$(".btn2").click(function(){
    $(".loadingicon").show();
    setTimeout(function(){
      $.ajax({
        url : "p.php",
        async : false,
        success: function(data){
          $(".loadingicon").hide();
          alert(data);
        }
      });
    }, 0);
}); 

Le deuxième paramètre de setTimeout est défini sur 0 et le navigateur l'exécutera après un temps minimum défini. Quoi qu'il en soit, commençons par le lancer et voyons.

L'image du chargement du résultat s'affiche, mais ! ! ! Pourquoi l'image ne bouge-t-elle pas ? C'est évidemment un gif animé. À ce moment-là, j'ai rapidement pensé que même si la demande de synchronisation était retardée, elle bloquerait toujours le thread de l'interface utilisateur lors de son exécution. Ce blocage est tellement génial que même l’image GIF ne bouge pas et ressemble à une image statique.

La conclusion est évidente. SetTimeout traite les symptômes mais pas la cause première. Cela équivaut à rendre la demande de synchronisation "légèrement" asynchrone. Cela entrera quand même dans un cauchemar de synchronisation et bloquera le thread. Le plan a échoué.

Il est temps d'utiliser le différé

jQuery a introduit l'objet Deferred après la version 1.5, qui fournit un mécanisme asynchrone généralisé très pratique. Pour plus de détails, veuillez vous référer à cet article de l'enseignant Ruan Yifeng http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html.

J'ai donc réécrit le code en utilisant des objets Deferred, comme suit :

function getData3(){
    var defer = $.Deferred();
    $.ajax({
      url : "p.php",
      //async : false,
      success: function(data){
        defer.resolve(data)
      }
    });
    return defer.promise();
}  
$(".btn3").click(function(){
    $(".loadingicon").show();
    $.when(getData3()).done(function(data){
      $(".loadingicon").hide();
      alert(data);
    });
});

Vous pouvez voir que j'ai supprimé async:false dans la requête ajax, ce qui signifie que la requête est à nouveau asynchrone. Veuillez également faire attention à cette phrase dans la fonction success : defer.resolve(data). La méthode de résolution de l'objet Deferred peut transmettre un paramètre de n'importe quel type. Ce paramètre peut être obtenu dans la méthode done, de sorte que les données que nous avons demandées de manière asynchrone peuvent être renvoyées de cette manière.

À ce stade, le problème a été résolu. Les objets différés sont si puissants et pratiques que nous pouvons en profiter.

Tous mes codes de test sont les suivants, les étudiants intéressés peuvent les utiliser pour tester :

<button class="btn1">async:false</button>
<button class="btn2">setTimeout</button>
<button class="btn3">deferred</button>
<img class="loadingicon" style="position:fixed;left:50%;top:50%;margin-left:-16px;margin-top:-16px;display:none;" src=http://www.update8.com/Web/Jquery/"loading2.gif" alt="正在加载" />
<script>
  function getData1(){
    var result;
    $.ajax({
      url : "p.php",
      async : false,
      success: function(data){
        result = data;
      }
    });
    return result;
  }
  $(".btn1").click(function(){
    $(".loadingicon").show();
    var data = getData1();
    $(".loadingicon").hide();
    alert(data);
  });
  $(".btn2").click(function(){
    $(".loadingicon").show();
    setTimeout(function(){
      $.ajax({
        url : "p.php",
        async : false,
        success: function(data){
          $(".loadingicon").hide();
          alert(data);
        }
      });
    }, 0);
  });
  function getData3(){
    var defer = $.Deferred();
    $.ajax({
      url : "p.php",
      //async : false,
      success: function(data){
        defer.resolve(data)
      }
    });
    return defer.promise();
  }  
  $(".btn3").click(function(){
    $(".loadingicon").show();
    $.when(getData3()).done(function(data){
      $(".loadingicon").hide();
      alert(data);
    });
  });</script>

ps : Description du paramètre de $.ajax

Description du paramètre

url obligatoire. Spécifie l'URL à laquelle la demande doit être envoyée.
les données sont facultatives. Valeur de mappage ou de chaîne. Spécifie les données à envoyer au serveur avec la requête.
success(data, textStatus, jqXHR) Facultatif. La fonction de rappel exécutée lorsque la demande réussit.
Type de données
Facultatif. Spécifie le type de données de la réponse attendue du serveur.
Le jugement intelligent est effectué par défaut (xml, json, script ou html).

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn