Maison  >  Article  >  interface Web  >  Solution au problème de blocage des threads de l'interface utilisateur causé par l'Ajax synchronisé par jQuery

Solution au problème de blocage des threads de l'interface utilisateur causé par l'Ajax synchronisé par jQuery

黄舟
黄舟original
2017-08-13 10:09:142172parcourir

Cet article présente principalement le problème de blocage des threads de l'interface utilisateur et les solutions provoquées par l'Ajax synchronisé avec jQuery. Il a une certaine valeur de référence. Ceux qui sont intéressés peuvent en apprendre davantage

Comme le dit le proverbe, si vous ne le faites pas. cherchez la mort, vous ne mourrez pas. Je me suis suicidé aujourd'hui et j'ai écrit une fonction relativement stupide. J'ai rencontré le problème de blocage des threads de l'interface utilisateur causé par l'Ajax synchronisé. Je vais l'enregistrer ici.

La raison est la suivante, car il existe plusieurs actions de requête asynchrone 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 renvoyer 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 dois ajouter une autre fonction Comme la requête ajax prend du temps, je dois avoir un effet de chargement sur la page avant de faire la requête. , c'est-à-dire qu'il affiche une image gif "Chargement", que tout le monde doit avoir vue. Ma fonction de traitement devient donc comme ceci :


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

Afficher l'image de chargement avant la requête et la masquer une fois la requête terminée. Il ne semble y avoir aucun problème. Afin de voir clairement l'effet, mon code p.php est en veille pendant 3 secondes, comme suit :


<?php
sleep(3);
echo (&#39;aaaaaa&#39;);
?>

Mais un problème est survenu lorsque je l'ai exécuté. cliqué sur le bouton, cela n'a pas fonctionné. L'image de chargement apparaît comme prévu, mais la page ne répond pas 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 dans la phrase avant le lancement de la requête, cette demande 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 où se situe 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 ceci :


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

Le deuxième paramètre de setTimeout est défini sur 0, et le navigateur le définira dans un délai d'exécution minimum défini. plus tard. 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, et cela entrera quand même dans un cauchemar de synchronisation et bloquera le thread. Le plan a échoué.

Il est temps d'utiliser Deferred

Après la version 1.5, jQuery a introduit l'objet Deferred, qui fournit un mécanisme asynchrone généralisé très pratique. Pour plus de détails, veuillez vous référer à cet article http://www.jb51.net/article/54762.htm.

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


function getData3(){
    var defer = $.Deferred();
    $.ajax({
      url : &#39;p.php&#39;,
      //async : false,
      success: function(data){
        defer.resolve(data)
      }
    });
    return defer.promise();
}  

$(&#39;.btn3&#39;).click(function(){
    $(&#39;.loadingicon&#39;).show();
    $.when(getData3()).done(function(data){
      $(&#39;.loadingicon&#39;).hide();
      alert(data);
    });
});

Vous pouvez voir que j'ai supprimé async:false dans la requête ajax, aussi C'est-à-dire que cette 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 le passer pour un test :


<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="loading2.gif" alt="正在加载" />
<script>

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

    return result;
  }

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


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



  function getData3(){
    var defer = $.Deferred();
    $.ajax({
      url : &#39;p.php&#39;,
      //async : false,
      success: function(data){
        defer.resolve(data)
      }
    });
    return defer.promise();
  }  

  $(&#39;.btn3&#39;).click(function(){
    $(&#39;.loadingicon&#39;).show();
    $.when(getData3()).done(function(data){
      $(&#39;.loadingicon&#39;).hide();
      alert(data);
    });
  });</script>

PS : Firefox est-il optimisé ?

Les problèmes ci-dessus ont été testés dans Chrome et IE9 et les conclusions sont cohérentes. Mais lorsque je l'ai testé dans Firefox, l'ajax synchronisé n'a pas bloqué le thread de l'interface utilisateur, ce qui signifie que ce problème n'existe pas du tout. Je l'ai testé avec d'autres codes. Dans Firefox, le thread js bloquera effectivement le thread UI. Cela ne fait aucun doute. Une hypothèse possible est que Firefox a optimisé l'ajax synchronisé. Je n'ai pas encore appris quel est le fait. Si quelqu'un sait, merci de me donner quelques conseils.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

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