注:測試瀏覽器為chrome瀏覽器
我們先來看第一段代碼:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>測試</title> </head> <body> <h1>Hello</h1> <script type="text/javascript"> let i = 1000000000 while(i>0){ i-- } </script> <h1>world</h1> </body> </html>
我們知道js會阻塞DOM解析和渲染,所以頁面肯定會在內聯script里的代碼執行完成之后,再渲染出來
答案確實是這樣
分析:一開始渲染進程的HTML 解析器開始解析DOM,當解析到內聯script 腳本標簽時,HTML 解析器會暫停解析DOM,此時JavaScript 引擎介入,並執行內聯script 標簽中的這段腳本,腳本執行完成之后,HTML 解析器恢復解析過程,繼續解析DOM,然后進行后續的渲染,最終將頁面上同時渲染出 Hello World
接下來,我們看第二段代碼:
index.js:
var i = 1000000000 while(i>0){ i-- }
index.html:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>測試</title> </head> <body> <h1>Hello</h1> <script type="text/javascript" src="index.js"></script> <h1>world</h1> </body> </html>
那這段html代碼的運行結果是不是和上面一樣呢?
剛開始我以為是,后來發現並不是這樣的,谷歌瀏覽器做了一些優化,所以執行結果會有一些變化
分析:當渲染引擎收到字節流之后,會開啟一個預解析線程,用來分析 HTML 文件中包含的 JavaScript、CSS 等相關文件,解析到相關文件之后,預解析線程會提前下載這些文件。因為這段html代碼里有外聯script腳本,所以會丟到預解析線程去下載這個外聯js文件,此時HTML 解析器開始解析DOM,當遇到外聯script標簽時,停止DOM解析,瀏覽器會渲染一次頁面(當前的Hello會被渲染到頁面上),然后執行下載完成的js文件,接着繼續解析DOM,然后進行后續的渲染,最終將頁面上就會渲染出 Hello World
注意:這里是先渲染出Hello ,然后過一會兒(這個期間在執行js),再渲染出World
答案:第一段代碼和第二段代碼的執行最終結果一樣,但是渲染順序不一樣。第一段代碼先間隔一段時間(執行js),然后Hello World會同時被渲染出來;第二段代碼會先渲染出Hello,然后間隔一段時間(執行js),再渲染出World
總結:
雖然js都會阻塞DOM解析,但是瀏覽器對於內聯script和外聯script的渲染過程還是有一點點不同。內聯js會阻塞DOM解析和渲染,直到js執行完成后,頁面才會被渲染出來。外聯js也會阻塞DOM解析和渲染,但是如果在外聯script標簽之前已經有DOM元素生成,則瀏覽器會優先渲染一次。我想這是因為瀏覽器不知道腳本的內容,因而碰到腳本時,只好先渲染頁面,確保腳本能獲取到最新的DOM
元素信息,盡管腳本可能不需要這些信息。
——個人理解,如有出錯,請指正——