Heim >Web-Frontend >js-Tutorial >Analysieren der Reihenfolge, in der Browser das Laden von JavaScript-Skripten ausführen, und die Codeausführung._Javascript-Fähigkeiten

Analysieren der Reihenfolge, in der Browser das Laden von JavaScript-Skripten ausführen, und die Codeausführung._Javascript-Fähigkeiten

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOriginal
2016-05-16 15:20:281707Durchsuche

Dieser Artikel basiert hauptsächlich auf verschiedenen Möglichkeiten, JavaScript in HTML-Seiten einzuführen, und analysiert die Ausführungsreihenfolge von JavaScript-Skripten in HTML

1. Bezüglich der blockierenden Natur der JavaScript-Skriptausführung

JavaScript weist Blockierungseigenschaften auf, wenn es im Browser analysiert und ausgeführt wird. Das heißt, wenn der JavaScript-Code ausgeführt wird, muss das Parsen, Rendern und Herunterladen anderer Ressourcen gestoppt und gewartet werden, bis das Skript abgeschlossen ist①. Dies ist unumstritten und das Verhalten ist in allen Browsern konsistent. Der Grund ist nicht schwer zu verstehen: Der Browser benötigt eine stabile DOM-Struktur, und JavaScript kann das DOM ändern (die DOM-Struktur ändern oder einen bestimmten DOM-Knoten ändern). Das Parsen der Seite wird fortgesetzt, während JavaScript ausgeführt wird. Dadurch wird der gesamte Parsing-Prozess schwer zu kontrollieren und die Wahrscheinlichkeit von Parsing-Fehlern wird ebenfalls sehr hoch.

Hier gibt es jedoch noch ein weiteres Problem, das Aufmerksamkeit erfordert. In früheren Browsern blockierte das Herunterladen von JavaScript-Dateien nicht nur das Parsen der Seite, sondern blockierte sogar andere Ressourcen auf der Seite Downloads (einschließlich anderer JavaScript-Skriptdateien, externer CSS-Dateien und externer Ressourcen wie Bilder). Ab IE8, Firefox3.5, Safari4 und Chrome2 ist das parallele Herunterladen von JavaScript zulässig. Gleichzeitig wird das Herunterladen anderer Ressourcen durch das Herunterladen von JavaScript-Dateien nicht blockiert (in älteren Versionen wird auch das Herunterladen von JavaScript-Dateien blockiert). das Herunterladen anderer Ressourcen).

Hinweis: Verschiedene Browser haben unterschiedliche Einschränkungen hinsichtlich der maximalen Anzahl von Verbindungen unter demselben Domänennamen. Die Anforderung in der HTTP1.1-Protokollspezifikation lautet, dass sie nicht höher als 2 sein darf, aber die meisten Browser bieten derzeit eine maximale Anzahl von Verbindungen . Mehr als 2, IE6/7 haben beide 2, IE8 wurde auf 6 aktualisiert, Firefox und Chrome haben auch 6. Einzelheiten finden Sie natürlich auch unter: http://. www.stevesouders. com/blog/2008/03/20/roundup-on-parallel-connections/

2. Über die Ausführungsreihenfolge des Skripts

Browser analysieren Seiten in der Reihenfolge von oben nach unten, sodass unter normalen Umständen auch die Ausführungsreihenfolge von JavaScript-Skripten von oben nach unten erfolgt, d. h. der Code, der zuerst auf der Seite erscheint, oder der Code, der zuerst eingeführt wird wird immer zuerst ausgeführt, auch wenn das parallele Herunterladen von JavaScript-Dateien erlaubt ist. Beachten Sie, dass wir hier „unter normalen Umständen“ rot markiert haben. Was ist der Grund? Wir wissen, dass es viele Möglichkeiten gibt, JavaScript-Code zu HTML hinzuzufügen, die wie folgt zusammengefasst sind (unabhängig von Modulladern wie requirejs oder seajs):

(1) Normale Einführung: das heißt, Einführung von Skriptcode oder Einführung externer Skripte über das 3f1c4e4b6b16bbbd69b2ee476dc4f83a-Tag auf der Seite

(2) Schreiben Sie 3f1c4e4b6b16bbbd69b2ee476dc4f83a-Tags oder Codes über die document.write-Methode
auf die Seite

(3) Mithilfe der dynamischen Skripttechnologie wird ein 3f1c4e4b6b16bbbd69b2ee476dc4f83a-Element mithilfe der DOM-Schnittstelle erstellt, der src des Elements festgelegt und das Element dann zum DOM hinzugefügt.

(4) Rufen Sie den Skriptinhalt über Ajax ab, erstellen Sie dann das 3f1c4e4b6b16bbbd69b2ee476dc4f83a-Element, legen Sie den Text des Elements fest und fügen Sie das Element dann dem DOM hinzu.

(5) Schreiben Sie JavaScript-Code direkt in den Event-Handler des Elements oder direkt als Textkörper der URL. Das Beispiel lautet wie folgt:

<!--直接写在元素的事件处理程序中-->
<input type="button" value="点击测试一下" onclick="alert('点击了按钮')"/>
<!--作为URL的主体-->
<a href="javascript:alert('dd')">JS脚本作为URL的主体</a> 

Der fünfte Fall hat keinen Einfluss auf die Reihenfolge der Skriptausführung, die wir besprechen, daher besprechen wir hier nur die ersten vier Fälle:

2.1 Bei normaler Einführung des Skripts

Wenn ein Skript normalerweise eingeführt wird, wird der JavaScript-Code von oben nach unten ausgeführt. Unabhängig davon, ob das Skript parallel heruntergeladen wird, wird es weiterhin von oben nach unten in der Reihenfolge der Einführung ausgeführt DEMO als Beispiel:

Schreiben Sie zunächst ein Skript über PHP. Dieses Skript empfängt zwei Parameter, die Datei-URL und die Verzögerungszeit. Das Skript sendet den Dateiinhalt nach der eingehenden Verzögerungszeit:

<&#63;php
$url = $_GET['url'];
$delay = $_GET['delay'];
if(isset($delay)){
sleep($delay);
}
echo file_get_contents($url);
&#63;> 

Darüber hinaus haben wir auch zwei JavaScript-Dateien definiert, nämlich 1.js und 2.js. In diesem Beispiel lauten die Codes der beiden wie folgt:

1.js

alert("Ich bin das erste Skript");

2.js

alert("Ich bin das zweite Skript");

Dann stellen wir den Skriptcode in HTML vor:

<script src='/delayfile.php&#63;url=http://localhost/js/load/1.js&delay=3' type='text/javascript'></script>
<script type="text/javascript">
alert("我是内部脚本");
</script>
<script src='/delayfile.php&#63;url=http://localhost/js/load/2.js&delay=1' type='text/javascript'></script> 

虽然第一个脚本延迟了3秒才会返回,但是在所有浏览器中,弹出的顺序也都是相同的,即:"我是第一个脚本"->"我是内部脚本"->"我是第二个脚本"

2.2 通过document.write向页面中写入脚本时

document.write在文档流没有关闭的情况下,会将内容写入脚本所在位置结束之后紧邻的位置,浏览器执行完当前短的代码,会接着解析document.write所写入的内容。

注:document.write写入内容的位置还存在一个问题,加入在93f0f5c25f18dab9d176bd4f6de5d30e内部的脚本中写入了93f0f5c25f18dab9d176bd4f6de5d30e标签内部不应该出现的内容,比如dc6dce4a544fdca2df29d5ac0ea9906b等内容标签等,则这段内容的起始位置将是6c04bd5ca3fcae76e30b72ad730ca86d标签的起始位置。

通过document.write写入脚本时存在一些问题,需要分类进行说明:

[1]同一个3f1c4e4b6b16bbbd69b2ee476dc4f83a标签中通过document.write只写入外部脚本:

在这种情况下,外部脚本的执行顺序总是低于引入脚本的标签内的代码,并且按照引入的顺序来执行,我们修改HTML中的代码:

<script src='/delayfile.php&#63;url=http://localhost/js/load/1.js&delay=2' type='text/javascript'></script>
<script type="text/javascript">
document.write('<script type="text/javascript" src="/delayfile.php&#63;url=http://localhost/js/load/2.js"><\/script>');
document.write('<script type="text/javascript" src="/delayfile.php&#63;url=http://localhost/js/load/1.js"><\/script>');
alert("我是内部脚本");
</script> 

这段代码执行完毕之后,DOM将被修改为:

而代码执行的结果也符合DOM中脚本的顺序:"我是第一个脚本"->"我是内部脚本"->"我是第二个脚本"->"我是第一个脚本"

[2]同一个3f1c4e4b6b16bbbd69b2ee476dc4f83a标签中通过document.write只写入内部脚本:

在这种情况下,通过documen.write写入的内部脚本,执行顺序的优先级与写入脚本标签内的代码相同,并且按照写入的先后顺序执行:

我们再修改HTML代码如下:

<script src='/delayfile.php&#63;url=http://localhost/js/load/1.js' type='text/javascript'></script>
<script type="text/javascript">
document.write('<script type="text/javascript">alert("我是docment.write写入的内部脚本")<\/script>');
alert("我是内部脚本");
document.write('<script type="text/javascript">alert("我是docment.write写入的内部脚本2222")<\/script>');
document.write('<script type="text/javascript">alert("我是docment.write写入的内部脚本3333")<\/script>');
</script> 

在这种情况下,document.write写入的脚本被认为与写入位置处的代码优先级相同,因此在所有浏览器中,弹出框的顺序均为:"我是第一个脚本"->"我是document.write写入的内部脚本"->"我是内部脚本"->"我是document.write写入的内部脚本2222"->"我是document.write写入的内部脚本3333"

[3]同一个3f1c4e4b6b16bbbd69b2ee476dc4f83a标签中通过document.write同时写入内部脚本和外部脚本时:

在这种情况下,不同的浏览器中存在一些区别:

在IE9及以下的浏览器中:只要是通过document.write写入的内部脚本,其优先级总是高于document.write写入的外部脚本,并且优先级与写入标签内的代码相同。而通过通过document.write写入的外部脚本,则总是在写入标签的代码执行完毕后,再按照写入的顺序执行;

而在其中浏览器中, 出现在第一个document.write写入的外部脚本之前的内部脚本,执行顺序的优先级与写入标签内的脚本优先级相同,而之后写入的脚本代码,不管是内部脚本还是外部脚本,总是要等到写入标签内的脚本执行完毕后,再按照写入的顺序执行。

我们修改以下HTML中的代码:

<script src='/delayfile.php&#63;url=http://localhost/js/load/1.js' type='text/javascript'></script><script type="text/javascript"> document.write('<script type="text/javascript">alert("我是docment.write写入的内部脚本")<\/script>'); alert("我是内部脚本"); document.write('<script type="text/javascript" src="/delayfile.php&#63;url=http://localhost/js/load/1.js"><\/script>'); document.write('<script type="text/javascript">alert("我是docment.write写入的内部脚本2222")<\/script>'); document.write('<script type="text/javascript" src="/delayfile.php&#63;url=http://localhost/js/load/1.js"><\/script>'); document.write('<script type="text/javascript">alert("我是docment.write写入的内部脚本3333")<\/script>'); alert("我是内部脚本2222");</script> 

在IE9及以下的浏览器中,上面代码执行后弹出的内容为:"我是第一个脚本"->"我是document.write写入的内部脚本"->"我是内部脚本"->"我是document.write写入的内部脚本2222"->"我是document.write写入的内部脚本3333"->"我是内部脚本2222"->"我是第一个脚本"->"我是第一个脚本"

其他浏览器中,代码执行后弹出的内容为:"我是第一个脚本"->"我是document.write写入的内部脚本"->"我是内部脚本"->"我是内部脚本2222"->"我是第一个脚本"->"我是document.write写入的内部脚本2222"->"我是第一个脚本"->"我是document.write写入的内部脚本3333"

如果希望IE及以下的浏览器与其他浏览器保持一致的行为,那么可选的做法就是把引入内部脚本的代码拿出来,单独放在后面一个新的3f1c4e4b6b16bbbd69b2ee476dc4f83a标签内即可,因为后面3f1c4e4b6b16bbbd69b2ee476dc4f83a标签中通过document.write所引入的代码执行顺序肯定是在之前的标签中的代码的后面的。

2.3 通过动态脚本技术添加代码时

通过动态脚本技术添加代码的主要目的在于创建无阻塞脚本,因为通过动态脚本技术添加的代码不会立刻执行,我们可以通过下面的load函数为页面添加动态脚本:

function loadScript(url,callback){
var script = document.createElement("script");
script.type = "text/javascript";
//绑定加载完毕的事件
if(script.readyState){
script.onreadystatechange = function(){
if(script.readyState === "loaded" || script.readyState === "complete"){
callback&&callback();
}
}
}else{
script.onload = function(){
callback&&callback();
}
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}

但是通过动态脚本技术添加的外部JavaScript脚本不保证按照添加的顺序执行,这一点可以通过回调或者使用jQuery的html()方法,详细可参考:http://www.jb51.net/article/26446.htm

2.4 通过Ajax注入脚本

通过Ajax注入脚本同样也是添加无阻塞脚本的技术之一,我们首先需要创建一个XMLHttpRequest对象,并且实现get方法,然后通过get方法取得脚本内容并注入到文档中。

代码示例:

我们可以用如下代码封装XMLHttpRequest对象,并封装其get方法:

var xhr = (function(){
function createXhr(){
var xhr ;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else if(window.ActiveXObject){
var xhrVersions = ['MSXML2.XMLHttp','MSXML2.XMLHttp.3.0','MSXML2.XMLHttp.6.0'], i, len;
for(i = 0, len = xhrVersions.length; i < len ; i++){
try{
xhr = new ActiveXObject(xhrVersions[i]);
}catch(e){
}
}
}else{
throw new Error("无法创建xhr对象");
}
return xhr;
}
function get(url,async,callback){
var xhr = createXhr();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
callback&&callback(xhr.responseText);
}else{
alert("请求失败,错误码为" + xhr.status);
}
}
}
xhr.open("get",url,async);
xhr.send(null);
}
return {
get:get
}
}()) 

然后基于xhr对象,再创建loadXhrScript函数:

function loadXhrScript(url,async, callback){ if(async == undefined){ async = true; } xhr.get(url,async,function(text){ var script = document.createElement("script"); script.type = "text/javascript"; script.text = text; document.body.appendChild(script); });} 

我们上面的get方法添加了一个参数,即是否异步,那么如果我们采用同步方法,通过Ajax注入的脚本肯定是按照添加的顺序执行;反之,如果我们采用异步的方案,那么添加的脚本的执行顺序肯定是无法确定的。

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