瀏覽器中Javascript的加載和執行


在剛學習Javascript時曾對該問題在小組內做個一次StudyReport,發現其中的基礎還是值得分析的。 

從標題分析,可以加個Javascript的加載和執行分為兩個階段:加載、執行。而加載即瀏覽器下載JS腳本的過程,執行時瀏覽器JS引擎解釋執行的過程。

接下來先分析JS腳本加載的過程,加載方式可分為同步加載和異步加載。

同步加載即瀏覽器加載JS過程中停止對HTML元素的解析,保證JS執行的安全一致性,但如果JS中包含大量計算時,會導致阻塞頁面的渲染。常見的JS加載是通過<script>標簽置於<head>內加載,這種方式會導致加載時阻塞對HTML元素的渲染,導致頁面短暫空白。因此,建議將<script>便簽置於</body>前,可以在HTML渲染完成后加載JS文件。即,

傳統加載方式:

<head>
<script src='yourscript.js'></script>
</head>
<body></body>

推薦加載方式:

<head></head>
<body>
...
<script src='yourscript.js'>
</script>
</body>

使用一個例子加上一張序列圖來描述HTML加載JS/CSS的流程,其中各個步驟均是同步的,會阻塞下一步解析。

<html>
<head>
<link></link>
<script><script>
</head>
<body>
<div></div>
<script></script>
</body>
</html>

  

異步加載也稱動態加載,即在后期動態加載JS。常見的動態JS加載有以下幾種方式。

1.document.write('yourscript.js');//這種方式在各瀏覽器行為不一致

2.動態修改<script></script>的src

3.動態插入<script>標簽,可在<script>腳本中,也可在onload中

<script> 
    var s = document.createElement('script'); 
    s.type = 'text/javascript'; 
    s.src = 'yourscript.js'; 
    var x = document.getElementsByTagName('script')[0]; 
    x.parentNode.insertBefore(s, x); 
</script> 

4.XHR結合eval

var xhr = new XmlHttpRequest();
xhr.onreadstatechange = function(){
    if(xhr.readyState==4)
    {
        if(xhr.status==200)
        {
             eval(xhr.responseText);
         }
    }
}
xhr.open("GET",yourscript.js',true);
xhr.send(null);

5.defer和async屬性。

<script src='yourscript.js' async/defer ></script>

二者都在onload之前執行完成,可用於不修改DOM的JS腳本加載。不同之處在與,defer下載的JS按順序執行,而async不能保證執行順序。

 

接下來分析腳本的執行流程。執行可分為解釋與執行兩個過程。

在腳本解釋的過程中,會對var和function做不同的處理,var定義的對象賦值undefined,而function定義的對象賦值為函數體。

我們用示例來解釋上面的意思。首先看解釋器對var的處理。

 

<script>
    alert(i); // undefined
    var i = 1;
    alert(i); 
</script>

上述代碼在解釋器中進行轉換為:

<script>
    var i;
    alert(i); // undefined
    i = 1;
    alert(i); 
</script>

這樣就能理解為什么i值為undefinded。接下來我們看看對function的處理。

<script>
    alert(func); // function(){alert('out')}
    var func = function(){
        alert('out');
    };
    alert(func); 
</script>

上述代碼在解釋器中進行轉換為:  

<script>
    var func = function(){
        alert('out');
    };
    alert(func); // function(){alert('out')}
    alert(func); 
</script>

這就是解釋器對var和function的不同處理,function的聲明和函數體定義都會被提前。

另外,腳本解釋過程中,以<script>以塊為單位執行,塊間可共享變量。對外部腳本會將JS加載完成並執行,而且JS腳本在執行的過程中會阻塞后續HTML頁面的渲染。

<script>
    alert(i); // error 該塊內后續代碼不執行
    i = 1;
    alert(i); 
</script>
<script>
    var j=0;    
    alert(j); //
</script>

上面這個例子解釋了腳本以塊為單位執行的原理,雖然第一個<script>會報異常,但並不影響第二個<script>的執行。

<script>
    var i = 1;
    alert(i); //1
</script>
<script>
    alert(i); //1
</script>

通過上例結果,可解釋兩個<script>之間是可以共享變量的。這也就是為什么加載jquery.min.js后,在任何<script>中都可以使用$來引用jQuery。 

 

關於瀏覽器加載JS並執行的過程暫時描述到此,后期繼續補充。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM