JavaScript 從下載到執行(阻塞、defer、async)

JavaScript 是如何工做的系列——第一篇

前言

咱們都知道在默認狀況下,JavaScript 的下載和執行會阻塞 HTML 的解析,結果會致使從打開頁面到顯示出網頁內容的過程耗時較長,用戶體驗很差。本篇文章主要介紹了 JavaScript 的下載和執行是如何阻塞 HTML 解析的 ,以及如何避免阻塞。javascript

JavaScript 的下載和執行

咱們如下面這段代碼爲例:html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo</title>
    <script src='./js/index1.js'></script>
    <script src='./js/index2.js'></script>
    <script src='./js/index3.js'></script>
</head>
<body>
    <div>Downloading Scripts to Execution</div>
</body>
</html>

index1.js 文件內容:java

console.log('index1');

index2.js 文件內容:git

console.log('index2');

index3.js 文件內容:github

console.log('index3);

當咱們在瀏覽器中打開上述 HTML 文件以後,瀏覽器就會開始解析 HTML 代碼。當瀏覽器遇到 <head> 標籤中的第一個 <script> 標籤(index1.js)後,HTML 的解析會暫停。此時瀏覽器會發送一個 HTTP 請求去下載 index1.js 文件,當腳本下載完成,瀏覽器開始解析並解釋執行下載的腳本( index1.js)。當 index1.js 執行完畢,瀏覽器繼續解析 HTML 代碼。當遇到第二個 <script> 標籤(index2.js)後,處理過程同上,後面依次類推。瀏覽器

Image  6

因而可知,腳本的數量與消耗的時間是成正比的。在<head> 標籤中引入的腳本越多,用戶等待的時間越長。async

避免阻塞方式

那麼有什麼辦法能夠解決上述問題呢?ui

最多見的方式就是將 <script> 標籤放到 HTML 文檔最後,</body>標籤以前。這會提升網頁加載速度,由於 HTML 加載再也不受制於腳本加載,當 HTML 內容解析完畢後,纔會開始加載腳本。spa

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo</title>
</head>
<body>
    <div>Downloading Scripts to Execution</div>
    <script src='./js/index1.js'></script>
    <script src='./js/index2.js'></script>
    <script src='./js/index3.js'></script>
</body>
</html>

固然還有兩種方式能夠解決上述問題:(只適用於外部腳本)線程

  • defer 屬性
  • async 屬性(HTML5)

defer

使用 defer 屬性後:

  • JavaScript 腳本下載在新的線程中進行,不會阻塞 HTML 解析;
  • 腳本下載完成後,不當即執行,在 HTML 解析完成後按照順序執行。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo</title>
    <script defer src='./js/index1.js'></script>
    <script defer src='./js/index2.js'></script>
    <script src='./js/index3.js'></script>
</head>
<body>
    <div>Downloading Scripts to Execution</div>
</body>
</html>

defer

async

使用 async 屬性後:

  • JavaScript 腳本下載在新的線程中進行,不會阻塞 HTML 解析;(同 defer)
  • 腳本下載完成後,當即解析,此時會阻塞 HTML 的解析。解析完畢後,在另外一個線程中解釋執行,此時不會阻塞 HTML 的解析。(多個腳本的執行順序沒法預測)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo</title>
    <script async src='./js/index1.js'></script>
    <script async src='./js/index2.js'></script>
    <script src='./js/index3.js'></script>
</head>
<body>
    <div>Downloading Scripts to Execution</div>
</body>
</html>

async

從上圖中能夠看到,JavaScript 腳本的執行順序是:index1.js -> index3.js -> index2.js,這可能與你預想的執行順序不一樣。這是由於使用 async 屬性的腳本,其執行順序與文件大小、下載速度、解析速度等息息相關。

總結

comparison

本文示例代碼已上傳到 github,感興趣的讀者能夠自行下載。本地運行後,觀察使用不一樣的方式引入 JavaScript 腳本後,頁面的加載速度。

下一篇

本篇文章主要介紹了瀏覽器是什麼時候開始下載和執行 JavaScript 的 ,以及阻塞 HTML 解析問題。下篇文章將深刻 JS 引擎,瞭解 JavaScript 代碼執行的具體流程。敬請期待。

參考:

The Journey of JavaScript: from Downloading Scripts to Execution - Part I
相關文章
相關標籤/搜索