JavaScript 在 DOM裙椭、CSSOM 和 JavaScript 執(zhí)行之間引入了大量新的依賴關(guān)系湘捎,從而可能導致瀏覽器在處理以及在屏幕上渲染網(wǎng)頁時出現(xiàn)大幅延遲:
- 腳本在文檔中的位置很重要蛾茉。
- 當瀏覽器遇到一個 script 標記時慧域,DOM 構(gòu)建將暫停侄非,直至腳本完成執(zhí)行。
- JavaScript 可以查詢和修改 DOM 與 CSSOM箫老。
- JavaScript 執(zhí)行將暫停封字,直至 CSSOM 就緒。
- “優(yōu)化關(guān)鍵渲染路徑”在很大程度上是指了解和優(yōu)化 HTML耍鬓、CSS 和 JavaScript 之間的依賴關(guān)系譜周叮。
解析器阻止與異步 JavaScript
默認情況下,JavaScript 執(zhí)行會“阻止解析器”:當瀏覽器遇到文檔中的腳本時界斜,它必須暫停 DOM 構(gòu)建,將控制權(quán)移交給 JavaScript 運行時合冀,讓腳本執(zhí)行完畢各薇,然后再繼續(xù)構(gòu)建 DOM。我們在前面的示例中已經(jīng)見過內(nèi)聯(lián)腳本的實用情況君躺。實際上峭判,內(nèi)聯(lián)腳本始終會阻止解析器,除非您編寫額外代碼來推遲它們的執(zhí)行棕叫。
通過 script 標簽引入的腳本又怎樣林螃?讓我們還用前面的例子,將代碼提取到一個單獨文件中:
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Critical Path: Script External</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
<script src="app.js"></script>
</body>
</html>
app.js
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);
無論我們使用 <script> 標記還是內(nèi)聯(lián) JavaScript 代碼段俺泣,您都可以期待兩者能夠以相同方式工作疗认。 在兩種情況下,瀏覽器都會先暫停并執(zhí)行腳本伏钠,然后才會處理剩余文檔横漏。不過,如果是外部 JavaScript 文件熟掂,瀏覽器必須停下來缎浇,等待從磁盤、緩存或遠程服務器獲取腳本赴肚,這就可能給關(guān)鍵渲染路徑增加數(shù)十至數(shù)千毫秒的延遲素跺。
默認情況下二蓝,所有 JavaScript 都會阻止解析器。由于瀏覽器不了解腳本計劃在頁面上執(zhí)行什么操作指厌,它會作最壞的假設并阻止解析器刊愚。向瀏覽器傳遞腳本不需要在引用位置執(zhí)行的信號既可以讓瀏覽器繼續(xù)構(gòu)建 DOM,也能夠讓腳本在就緒后執(zhí)行仑乌;例如百拓,在從緩存或遠程服務器獲取文件后執(zhí)行。
為此晰甚,我們可以將腳本標記為異步:
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Critical Path: Script Async</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
<script src="app.js" async></script>
</body>
</html>
向 script 標記添加異步關(guān)鍵字可以指示瀏覽器在等待腳本可用期間不阻止 DOM 構(gòu)建衙传,這樣可以顯著提升性能。