js加載時間線
在js加載開始的時候,瀏覽器會去記錄js執行的這段過程
1. 創建Document對象,開始解析web頁面。解析HTML元素和他們的文本內容後添加Element對象和Text節點到文檔中。這個階段document.readyState = 'loading'。
2. 遇到link外部css,創建線程加載,並繼續解析文檔。
3. 遇到script外部js,並且沒有設置async、defer,瀏覽器加載,並阻塞,等待js加載完成並執行該腳本,然後繼續解析文檔。
4. 遇到script外部js,並且設置有async、defer,瀏覽器創建線程加載,並繼續解析文檔。
對於async屬性的腳本,腳本加載完成後立即執行。(異步禁止使用document.write())
5. 遇到img等,先正常解析dom結構,然後瀏覽器異步加載src,並繼續解析文檔。
6. 當文檔解析完成,document.readyState = 'interactive'。
7. 文檔解析完成後,所有設置有defer的腳本會按照順序執行。(注意與async的不同,但同樣禁止使用document.write());
8. document對象觸發DOMContentLoaded事件,這也標誌着程序執行從同步腳本執行階段,轉化爲事件驅動階段。
9. 當所有async的腳本加載完成並執行後、img等加載完成後,document.readyState = 'complete',window對象觸發load事件。
10. 從此,頁面以異步響應方式處理用戶輸入,網絡事件等。
通過代碼來看(特別好理解)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
// 上面的是指文檔加載完成後,也就是時間線的第九步,纔會去執行裏面的方法
window.onload = function (){
var div = document.getElementsByTagName('div')[0];
console.log('這個肯定是在complete後面');
}
// 這樣子也是就說 當文檔解析完成後,就會去執行裏面的函數
document.addEventListener('DOMContentLoaded',function (){
var div = document.getElementsByTagName('div')[0];
console.log("這個肯定發生在complete前面"+div);
},false);
</script>
</head>
<body>
<div style="width:100px;height:100px;background-color:red;"></div>
<script>
console.log(document.readyState);
document.onreadystatechange = function (){
console.log(document.readyState);
}
</script>
</body>
</html>
自然而然會有三個狀態,也驗證了時間線是正確的