Es wird angenommen, dass es sich bei den Verzögerungs- und Asynchronisierungsfunktionen um zwei Funktionen handelt, mit denen viele JavaScript-Entwickler „vertraut, aber nicht vertraut“ sind. Im wahrsten Sinne des Wortes sind die Funktionen der beiden leicht zu verstehen. bzw. „asynchrones Skript“. Am Beispiel der Verzögerung sind Entwickler jedoch möglicherweise nicht unbedingt mit einigen Details vertraut, z. B.: Wann wird die Ausführung eines Skripts mit der Verzögerungsfunktion verzögert? Zusätzlich zur verzögerten Ausführung, was sind die Besonderheiten usw. Dieser Artikel kombiniert einige vorhandene Artikel und die Beschreibung der beiden Funktionen in MDN-Dokumenten, um eine umfassendere Studie und Zusammenfassung von Defer und Async durchzuführen und Entwicklern dabei zu helfen, diese beiden Funktionen besser zu beherrschen.
1 Einleitung
In „Analyse des Ladens und Ausführens von JavaScript-Skripten in der Browserumgebung: Codeausführungssequenz“ haben wir erwähnt, dass die Ausführung von JavaScript-Code das Parsen und Rendern der Seite sowie das Herunterladen anderer Ressourcen blockiert Da es sich bei JavaScript um eine Single-Thread-Sprache handelt, kann der JavaScript-Code auf einer Seite natürlich nur in der Reihenfolge „Analyse von JavaScript“ ausgeführt werden Laden und Ausführen von Skripten in der Browserumgebung Wie wir in „Ausführungssequenz “ analysiert haben, ist die Ausführungsreihenfolge von JavaScript-Code in einigen Fällen, beispielsweise bei der Eingabe eines Skripts über document.write oder der Einführung eines Skripts über dynamische Skripttechnologie, unterschiedlich Nicht unbedingt die strikte Reihenfolge von oben nach unten einhalten und asynchronisieren sind auch das, was wir als „abnormale Situationen“ bezeichnen.
Wir sagen oft, dass die Ausführung von JavaScript blockiert. In der tatsächlichen Entwicklung sollten die folgenden Aspekte die Blockierung sein, die uns normalerweise am meisten beschäftigt und die das Benutzererlebnis am meisten beeinträchtigt:
[1] Blockierung der Seitenanalyse und -wiedergabe
[2] Das von uns geschriebene Seiteninitialisierungsskript (im Allgemeinen das Skript, das das DOMContentLoaded-Ereignis abhört). Dieser Teil des Skripts ist der Skript, den wir zuerst ausführen möchten, da wir den Code schreiben, der für die Benutzerinteraktion am relevantesten ist hier. )
[3] Blockierung des Herunterladens externer Ressourcen auf der Seite (z. B. Bilder)
Wenn wir einen zeitaufwändigen Skriptvorgang haben und dieses Skript die drei oben genannten Stellen blockiert, ist die Leistung oder Benutzererfahrung dieser Webseite sehr schlecht.
Die ursprüngliche Absicht der beiden Funktionen „Defer“ und „Async“ besteht auch darin, die Auswirkungen des Blockierens auf das Seitenerlebnis zu lösen oder zu mildern. Wir verstehen diese beiden Funktionen hauptsächlich unter folgenden Gesichtspunkten: >
2-Verzögerungsfunktion
2.1 Informationen zum Ausführungszeitpunkt des Verzögerungsskripts
2.2 Browser-Unterstützung zurückstellen
Werfen wir einen Blick auf die Browserunterstützung für die Verzögerungsfunktion:
Es gibt einen Fehler in IE9 und niedrigeren Browsern, der später in der DEMO ausführlich erläutert wird.
2.3 DEMO: Funktionsüberprüfung der Verzögerungsfunktion
Wir imitieren die von Olivier Rochard im „Skript-Defer-Attribut“ verwendete Methode, um die Funktion des Defer-Attributs zu überprüfen:
Zuerst haben wir 6 externe Skripte vorbereitet:
1.js:
test = „Ich bin Leiter externes Skript n“;
3.js
test = „Ich bin das unterste externe Skript n“;
defer1.js
test = „Ich bin Leiter des externen Verzögerungsskripts n“;
defer3.js
test = „Ich bin das unterste externe Verzögerungsskript n“;
Der Code in HTML lautet:
Um die Implementierung des DOMContentLoaded-Ereignisses zu erleichtern, haben wir jQuery eingeführt (in späteren Artikeln erfahren Sie, wie Sie kompatibles DOMContentLoaded selbst implementieren. Anschließend haben wir Verzögerungsskripte im Kopf, innerhalb des Körpers und außerhalb des Codes eingeführt). Hauptteil des Skripts und normaler Skripte und zeichnet den Ausführungsstatus jedes Codeabschnitts über eine globale Zeichenfolge auf. Werfen wir einen Blick auf die Ausführungsergebnisse in jedem Browser:
IE7 | IE9 | IE10 | CHROM | Firefox | ||||||||||
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>defer attribute test</title> <script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script> <script type="text/javascript">var test = "";</script> <script src="defer1.js" type="text/javascript" defer="defer"></script> <script src="1.js" type="text/javascript"></script> <script defer="defer"> test += "我是head延迟内部脚本\n"; </script> <script> test += "我是head内部脚本\n"; </script> </head> <body> <button id="test">点击一下</button> <script src="defer2.js" type="text/javascript" defer="defer"></script> <script src="2.js" type="text/javascript"></script> </body> <script src="defer3.js" type="text/javascript" defer="defer"></script> <script src="3.js" type="text/javascript"></script> <script> $(function(){ test += "我是DOMContentLoaded里面的脚本 "; }) window.onload = function(){ test += "我是window.onload里面的脚本 "; var button = document.getElementById("test"); button.onclick = function(){ alert(test); } } </script> </html> Nach dem Login kopieren
Ich bin ein körperfremdes Skript Ich bin Kopfverzögerung internes Skript
|
<🎜>Ich bin Leiter des externen Skripts<🎜> Ich bin der Leiter des internen Skripts<🎜> Ich bin ein körperfremdes Skript<🎜> Ich bin das unterste externe Skript <🎜> Ich bin der Leiter des externen Verzögerungsskripts <🎜> Ich bin Kopfverzögerung internes Skript<🎜> Ich bin ein Body-External-Delay-Skript <🎜> Ich bin das unterste externe Verzögerungsskript <🎜> Ich bin das Skript in DOMContentLoaded<🎜> Ich bin das Skript in window.onload<🎜> | <🎜>Ich bin Leiter des externen Skripts<🎜> Ich bin ein kopfverzögertes internes Skript<🎜> Ich bin der Leiter des internen Skripts<🎜> Ich bin ein körperfremdes Skript<🎜> Ich bin das unterste externe Skript <🎜> Ich bin der Leiter des externen Verzögerungsskripts <🎜> Ich bin ein Body-External-Delay-Skript <🎜> Ich bin das unterste externe Verzögerungsskript <🎜> Ich bin das Skript in DOMContentLoaded<🎜> Ich bin das Skript in window.onload<🎜> | <🎜>Ich bin Leiter des externen Skripts<🎜> Ich bin ein kopfverzögertes internes Skript<🎜> Ich bin der Leiter des internen Skripts<🎜> Ich bin ein körperfremdes Skript<🎜> Ich bin das unterste externe Skript <🎜> Ich bin der Leiter des externen Verzögerungsskripts <🎜> Ich bin ein Body-External-Delay-Skript <🎜> Ich bin das unterste externe Verzögerungsskript <🎜> Ich bin das Skript in DOMContentLoaded<🎜> Ich bin das Skript in window.onload<🎜> | <🎜> |
从输出的结果中我们可以确定,只有IE9及以下浏览器支持内部延迟脚本,并且defer后的脚本都会在DOMContentLoaded事件之前触发,因此也是会堵塞DOMContentLoaded事件的。
2.4 DEMO:IE<=9的defer特性bug
从2.3节中的demo可以看出,defer后的脚本还是能够保持执行顺序的,也就是按照添加的顺序依次执行。而在IE<=9中,这个问题存在一个bug:假如我们向文档中增加了多个defer的脚本,而且之前的脚本中有appendChild,innerHTML,insertBefore,replaceChild等修改了DOM的接口调用,那么后面的脚本可能会先于该脚本执行。可以参考github的issue:https://github.com/h5bp/lazyweb-requests/issues/42
我们通过DEMO验证一下,首先修改1.js的代码为(这段代码只为模拟,事实上这段代码存在极大的性能问题):
document.body.innerHTML = "
2.js
alert("我是第2个脚本");
修改HMTL中的代码为:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>defer bug in IE=9 test</title> <script src="1.js" type="text/javascript" defer="defer"></script> <script src="2.js" type="text/javascript" defer="defer"></script> </head> <body> </body> </html>
正常情况下,浏览器中弹出框的顺序肯定是:我是第1个脚本-》我是第2个脚本,然而在IE<=9中,执行结果却为:我是第2个脚本-》我是第1个脚本,验证了这个bug。
2.5 defer总结
在总结之前,首先要说一个注意点:正如标准中提到的,defer的脚本中不应该出现document.write的操作,浏览器会直接忽略这些操作。
总的来看,defer的作用一定程度上与将脚本放置在页面底部有一定的相似,但由于IE<=9中的bug,如果页面中出现多个defer时,脚本的执行顺序可能会被打乱从而导致代码依赖可能会出错,因此实际项目中很少会使用defer特性,而将脚本代码放置在页面底部可以替代defer所提供的功能。
3 async特性
3.1 关于async脚本的执行时机
async特性是HTML5中引入的特性,使用方式为:async="async",我们首先看一下标准中对于async特性的相关描述:
async:If the async attribute is present, then the script will be executed asynchronously, as soon as it is available.
需要指出,这里的异步,指的其实是异步加载而不是异步执行,也就是说,浏览器遇到一个async的script标签时,会异步的去加载(个人认为这个过程主要是下载的过程),一旦加载完毕就会执行代码,而执行的过程肯定还是同步的,也就是阻塞的。我们可以通过下图来综合理解defer和async:
这样来看的话,async脚本的执行时机是无法确定的,因为脚本何时加载完毕也是不确定的。我们通过下面的demo来感受一下:
async1.js
alert("我是异步的脚本");
HTML代码:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>async attribute test</title> <script src="/delayfile.php?url=http://localhost/js/load/async1.js&delay=2" async="async" type="text/javascript"></script> <script> alert("我是同步的脚本"); </script> </head> <body> </body> </html>
Di sini kami meminjam skrip delayfile dalam "Analisis Pemuatan dan Pelaksanaan Skrip JavaScript dalam Persekitaran Penyemak Imbas: Urutan Pelaksanaan Kod" untuk memberikan kelewatan dalam penyemak imbas yang menyokong async, susunan kotak pop timbul skrip ini secara amnya : Saya skrip segerak -> Saya skrip tak segerak.
3.2 Sokongan penyemak imbas untuk tak segerak
Mari kita lihat sokongan penyemak imbas untuk ciri async:
Seperti yang anda lihat, hanya IE10 menyokong ciri async, opera mini tidak menyokong ciri async dan async tidak menyokong skrip dalaman.
Ringkasan tak segerak 3.3
async merujuk kepada skrip tak segerak, iaitu, skrip dimuatkan secara tidak segerak Proses pemuatan tidak akan menyebabkan penyekatan, tetapi masa pelaksanaan skrip async tidak pasti, dan susunan pelaksanaan juga tidak pasti, jadi skrip yang menggunakan async haruslah. Skrip yang tidak bergantung pada sebarang kod (seperti kod statistik pihak ketiga atau kod pengiklanan), jika tidak, ia akan menyebabkan ralat pelaksanaan.
4 Isu keutamaan antara tangguh dan tak segerak
Ini lebih mudah difahami. Standard menetapkan:
[1] Jika elemen
[2] Jika elemen
[3] Jika elemen