Heim > Web-Frontend > js-Tutorial > Analyse des Ladens und Ausführens von JavaScript-Skripten in einer Browserumgebung: Eigenschaften verzögern und asynchronisieren_Javascript-Fähigkeiten

Analyse des Ladens und Ausführens von JavaScript-Skripten in einer Browserumgebung: Eigenschaften verzögern und asynchronisieren_Javascript-Fähigkeiten

WBOY
Freigeben: 2016-05-16 15:20:02
Original
1651 Leute haben es durchsucht

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: >

[1]Wann ist die Ausführungszeit verzögerter oder asynchroner Skripte? Was ist mit der Seitenblockierung?


[2] Können sowohl interne als auch externe Skripte verzögert oder asynchron implementiert werden?


[3] Wie gut unterstützen Browser diese beiden Funktionen? Gibt es damit zusammenhängende Fehler?


[4] Muss bei der Verwendung von Skripten, die diese beiden Funktionen verwenden, noch etwas beachtet werden?


2-Verzögerungsfunktion

2.1 Informationen zum Ausführungszeitpunkt des Verzögerungsskripts

Die Verzögerungsfunktion ist eine erweiterte Funktion, die in der HTML4-Spezifikation definiert ist. Ursprünglich wurde sie nur von IE4 und Firefox 3.5 unterstützt. Später wurde sie auch von Browsern wie Chrome unterstützt, die defer="defer" verwenden. defer bedeutet Verzögerung, was bedeutet, dass die Ausführung des Skripts verzögert wird. Unter normalen Umständen wird das von uns eingeführte Skript sofort heruntergeladen und ausgeführt. Mit der Verzögerungsfunktion wird das Skript jedoch nicht sofort nach dem Herunterladen ausgeführt, sondern nach dem Parsen der Seite. Werfen wir einen Blick auf die Erklärung des HTML4-Standards zur Verzögerung:


defer: Wenn dieses boolesche Attribut festgelegt ist, gibt es dem Benutzeragenten einen Hinweis, dass das Skript keinen Dokumentinhalt generieren wird (z. B. kein „document.write“ in Javascript) und der Benutzeragent daher mit der Analyse fortfahren kann und Rendern.


Mit anderen Worten: Wenn die Verzögerung festgelegt ist, teilt es dem Benutzeragenten mit, dass dieses Skript keinen Dokumentinhalt erzeugen wird, sodass der Benutzeragent weiterhin analysieren und rendern kann. Schauen wir uns noch einmal die Schlüsselbeschreibung von defer in MDN an:


defer: Wenn das async-Attribut nicht vorhanden ist, aber das defer-Attribut vorhanden ist, wird das Skript ausgeführt, wenn die Seite mit dem Parsen fertig ist


Durch die Definition im Standard können wir klarstellen, dass das Verzögerungsskript das Parsen der Seite nicht blockiert, sondern mit der Ausführung wartet, bis das Parsen der Seite abgeschlossen ist. Das zeitaufwändige Verzögerungsskript kann jedoch trotzdem ausgeführt werden Blockieren Sie den Download externer Ressourcen. Wird dadurch das DOMContentLoaded-Ereignis blockiert? Tatsächlich wird das Verzögerungsskript immer noch vor dem DOMContentLoaded-Ereignis ausgeführt, sodass das Skript weiterhin in DOMContentLoaded blockiert wird. Wir können die folgende Abbildung verwenden, um den Ausführungszeitpunkt des Verzögerungsskripts zu verstehen:



Gemäß der Definition im Standard unterstützen interne Skripte keine Verzögerung, aber Browser IE9 und niedriger bieten Verzögerungsunterstützung für interne Skripte.


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“;

2.js


test = „Ich bin ein Körper externes Skript n“;


3.js


test = „Ich bin das unterste externe Skript n“;

defer1.js

test = „Ich bin Leiter des externen Verzögerungsskripts n“;

defer2.js


test = „Ich bin ein externes Verzögerungsskript 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 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

IE7 IE9 IE10 CHROME firefox

我是head外部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是head延迟内部脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

我是head外部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是head延迟内部脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

我是head外部脚本
我是head延迟内部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

我是head外部脚本
我是head延迟内部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

<br />我是head外部脚本
<span style="color: rgb(255,0,0)">我是head延迟内部脚本</span>
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是body外部延迟脚本
我是底部外部延迟脚本
<span style="color: rgb(255,0,0)">我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本</span>
Nach dem Login kopieren
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 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 = "

我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
alert("我是第1个脚本");

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>
Nach dem Login kopieren

正常情况下,浏览器中弹出框的顺序肯定是:我是第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&#63;url=http://localhost/js/load/async1.js&delay=2" async="async" type="text/javascript"></script>
<script>
alert("我是同步的脚本");
</script>
</head>
<body>
</body>
</html> 
Nach dem Login kopieren

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 mentakrifkan kedua-dua atribut defer dan async, ia akan diproses sebagai async (nota: penyemak imbas yang tidak menyokong async akan langsung mengabaikan atribut async)

[2] Jika elemen hanya mentakrifkan penangguhan, ia akan diproses sebagai skrip tertunda

[3] Jika elemen tidak mentakrifkan tangguh atau tak segerak, ia akan diproses seperti biasa, iaitu: skrip akan dimuatkan dan dilaksanakan serta-merta

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage