Heim >Web-Frontend >js-Tutorial >Lösung für das Problem der Blockierung von UI-Threads, das durch jQuery-synchronisiertes Ajax verursacht wird
Dieser Artikel stellt hauptsächlich das Problem der UI-Thread-Blockierung vor, das durch jQuery-synchronisiertes Ajax verursacht wird. Es hat einen bestimmten Referenzwert.
Wie das Sprichwort sagt, wenn Sie es nicht tun Suche den Tod, du wirst heute nicht sterben und eine relativ dumme Funktion geschrieben, die durch synchronisiertes Ajax verursacht wird.
Der Grund dafür ist, dass es auf der Seite mehrere ähnliche asynchrone Anforderungsaktionen gibt. Um die Wiederverwendbarkeit des Codes zu verbessern, habe ich eine Funktion namens getData gekapselt, die verschiedene Parameter empfängt und nur für den Datenabruf verantwortlich ist und dann die Daten zurückgeben. Die grundlegende Logik lautet wie folgt:
function getData1(){ var result; $.ajax({ url : 'p.php', async : false, success: function(data){ result = data; } }); return result; }
Der Ajax hier kann nicht asynchron sein, sonst wurde dem Ergebnis bei der Rückkehr der Funktion kein Wert zugewiesen, und Es wird ein Fehler auftreten. Also habe ich async:false hinzugefügt. Es scheint, als gäbe es kein Problem. Ich kann die Daten normal abrufen, indem ich diese Funktion aufrufe.
$('.btn1').click(function(){ var data = getData1(); alert(data); });
Als nächstes muss ich eine weitere Funktion hinzufügen. Da die Ajax-Anfrage zeitaufwändig ist, muss ich einen Ladeeffekt auf der Seite haben, bevor ich die Anfrage stelle , das heißt, es wird ein „Laden“-GIF-Bild angezeigt, das jeder gesehen haben muss. Meine Verarbeitungsfunktion sieht also so aus:
$('.btn1').click(function(){ $('.loadingicon').show(); var data = getData1(); $('.loadingicon').hide(); alert(data); });
Zeigen Sie das Ladebild vor der Anfrage an und blenden Sie es aus, nachdem die Anfrage abgeschlossen ist. Es scheint kein Problem zu geben. Um den Effekt deutlich zu sehen, schläft mein p.php-Code 3 Sekunden lang wie folgt:
<?php sleep(3); echo ('aaaaaa'); ?>
Als ich ihn ausführte, trat jedoch ein Problem auf Ich habe auf die Schaltfläche geklickt, es hat nicht funktioniert. Das Ladebild erscheint wie erwartet, aber die Seite reagiert überhaupt nicht. Nach langer Fehlerbehebung habe ich den Grund gefunden, der async:false ist.
Der Rendering-Thread (UI) des Browsers und der JS-Thread schließen sich gegenseitig aus. Wenn zeitaufwändige JS-Vorgänge ausgeführt werden, wird das Rendern der Seite blockiert. Es gibt kein Problem, wenn wir asynchrones Ajax ausführen, aber wenn es auf eine synchrone Anforderung eingestellt ist, werden andere Aktionen (der Code hinter der Ajax-Funktion und der Rendering-Thread) gestoppt. Selbst wenn meine DOM-Operationsanweisung im Satz steht, bevor die Anforderung initiiert wird, blockiert diese Synchronisierungsanforderung den UI-Thread „schnell“, ohne ihm Zeit zur Ausführung zu geben. Aus diesem Grund schlägt der Code fehl.
setTimeout löst das Blockierungsproblem
Da wir nun verstanden haben, wo das Problem liegt, wollen wir eine Lösung finden. Um zu verhindern, dass die synchrone Ajax-Anfrage den Thread blockiert, dachte ich an setTimeout, füge den Anforderungscode in sestTimeout ein und lasse den Browser einen Thread neu starten, um zu funktionieren. Wäre das Problem nicht gelöst? Seitdem sieht mein Code so aus:
$('.btn2').click(function(){ $('.loadingicon').show(); setTimeout(function(){ $.ajax({ url : 'p.php', async : false, success: function(data){ $('.loadingicon').hide(); alert(data); } }); }, 0); });
Der zweite Parameter von setTimeout ist auf 0 gesetzt und der Browser setzt ihn innerhalb einer festgelegten Mindestzeit. später hingerichtet. Egal was passiert, lassen Sie es uns zuerst ausführen und sehen.
Das Ergebnis-Ladebild wird angezeigt, aber! ! ! Warum bewegt sich das Bild nicht? Es ist offensichtlich ein animiertes GIF. Zu diesem Zeitpunkt dachte ich schnell, dass die Synchronisierungsanforderung zwar verzögert war, den UI-Thread jedoch während seiner Ausführung blockieren würde. Diese Blockierung ist so großartig, dass sich selbst das GIF-Bild nicht bewegt und wie ein statisches Bild aussieht.
Die Schlussfolgerung liegt auf der Hand. SetTimeout behandelt die Symptome, aber nicht die Grundursache. Dies ist gleichbedeutend damit, dass die Synchronisierungsanforderung „leicht“ asynchron ist und dann immer noch in einen Synchronisierungsalbtraum gerät und den Thread blockiert. Der Plan scheiterte.
Es ist Zeit, Deferred zu verwenden
Nach Version 1.5 führte jQuery das Deferred-Objekt ein, das einen sehr praktischen verallgemeinerten asynchronen Mechanismus bietet. Einzelheiten finden Sie in diesem Artikel http://www.jb51.net/article/54762.htm.
Also habe ich den Code mit einem Deferred-Objekt wie folgt umgeschrieben:
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); }); });
Sie können sehen, dass ich async:false in der Ajax-Anfrage entfernt habe , auch Das heißt, diese Anfrage ist wieder asynchron. Bitte beachten Sie auch diesen Satz in der Erfolgsfunktion: defer.resolve(data) Die Auflösungsmethode des Deferred-Objekts kann einen Parameter eines beliebigen Typs übergeben. Dieser Parameter kann in der Methode done abgerufen werden, sodass die von uns asynchron angeforderten Daten auf diese Weise zurückgegeben werden können.
Zu diesem Zeitpunkt ist das Problem gelöst. Aufgeschobene Objekte sind so leistungsstark und praktisch, dass wir sie nutzen können.
Alle meine Testcodes lauten wie folgt:
<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 : '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: Ist Firefox optimiert?
Die oben genannten Probleme wurden in Chrome und IE9 getestet und die Schlussfolgerungen sind konsistent. Aber als ich es in Firefox getestet habe, blockierte synchronisiertes Ajax den UI-Thread nicht, was bedeutet, dass dieses Problem überhaupt nicht besteht. Ich habe es mit anderen Codes getestet. Daran besteht kein Zweifel. Eine mögliche Vermutung ist, dass Firefox synchronisiertes Ajax optimiert hat. Ich habe noch nicht herausgefunden, was das ist. Wenn es jemand weiß, gebt mir bitte einen Rat.
Das obige ist der detaillierte Inhalt vonLösung für das Problem der Blockierung von UI-Threads, das durch jQuery-synchronisiertes Ajax verursacht wird. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!