不知道大家有沒有使用過 preload,preload
用來明確告知瀏覽器,某一份資源是很重要的,所以請優先下載它,使用方式如下:
<head>
<link
rel="preload"
as="style"
href="important-style.css"
</link>
</head>
而 module worker 也有一個類似的用法,使用 modulepreload 使得 worker 的載入速度變快
<!DOCTYPE html>
<html>
<head>
<!-- 預先加載重要的 worker.mjs 檔案 -->
<link rel="modulepreload" href="worker.mjs" />
<script src="./src/index.mjs" type="module"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
因為 modulepreload 是比較新的用法,不一定各大瀏覽器都有支援,而驗證的方法可以開啟 devtool 的 network 選項,查看 worker.mjs
是否會在 index.mjs
前被載入,這裡有個 範例 Demo 可以驗證,當使用兩種不同的寫法,在 network 中瀏覽器載入檔案的順序會不同,加了 <link rel="modulepreload" href="worker.mjs" />
這一行後,worker.mjs
會提早在 src/index.mjs
之前載入。
worker.mjs
在 index.mjs
之前載入:
在 MDN 中 modulepreload
的部分提到了:
A browser may additionally also choose to automatically fetch any dependencies of the module resource.
瀏覽器可以額外選擇自動的加載模塊中用到的所有依賴模塊。
關於這點這個 範例 Demo 中也有進行測試,可以看到 add.mjs
被 worker.js
依賴,但沒有寫在 modulepreload
裡,如果瀏覽器會自動加載所有依賴模塊的話,add.mjs
應該也會提前加載,但我實測 Chrome 116
瀏覽器,add.mjs
會在最後才被加載,代表瀏覽器目前應該沒有實作此功能。
Links with rel="modulepreload" are similar to those with rel="preload". The main difference is that preload just downloads the file and stores it in the cache, while modulepreload gets the module, parses and compiles it, and puts the results into the module map so that it is ready to execute.
基本上 modulepreload
跟 preload
是很相似的,但有一個主要的不同點在於,preload
只預先下載檔案並把它快取在瀏覽器中,然而 modulepreload
做到的更多,它更進一步的 解析 (parse) 而且 編譯 (compile) Javascript
模塊。
一開始看到這段想說 modulepreload
跟 preload
其實沒什麼差別,不過就是多進行了 解析 (parse) 跟 編譯 (compile) 而已,但深入瞭解後發現這其中是一段非常複雜的過程,關於這過程的解釋會放在最後的 補充小知識 2. Javascript 的 解析(parse) 與 編譯(compile)。
module worker
可以使用 rel="modulepreload"
的方式告知瀏覽器將重要的 worker
檔案優先下載,優化資源下載的流程
1. preload 是什麼?
preload 指令用來明確的告知瀏覽器,這份資源檔案很重要,請優先加載這份資料!通常會用到這個指令的場景是希望優先加載一些被寫在很深層的內嵌 css
或字型檔等,像以下的狀況,important-font.woff2
這個字型檔可能被嵌套在很深的 css
中
index.html
main.js
styles/
main.css
...
...
font.css
important-font.woff2
那麼在 index.html 中就可以使用 preload
告知瀏覽器先行下載 important-font.woff2
這個字型檔
<head>
<meta charset="utf-8">
<title>Preload example</title>
<!-- 明確告知瀏覽器,優先加載某個很深路徑的字型檔 -->
<link
rel="preload"
href="styles/very/deep/path/important-font.woff2"
as="font"
type="font/woff2"
crossorigin
</link>
<link href="styles/main.css" rel="stylesheet" />
</head>
在不加 preload
的一般狀況下,瀏覽器會優先讀取到 styles/main.css
,然後再往下讀取 styles/main.css
中用到了哪些其他的 css
或是字型檔,等到瀏覽器解析到 important-font.woff2
這份檔案時,已經過去一段時間了,而這時瀏覽器才會開始去抓這份重要的字型檔,而使用 preload
後可以明確告知瀏覽器這是重要的資源,請幫我優先下載它
想了解更多的推薦以下文章:
[教學] Preload, Prefetch 和 Preconnect 的差異
HTTP/2 服务器推送(Server Push)教程
2. Javascript 的 解析(parse) 與 編譯(compile)
相信大家一定都有聽過 Chrome
用來處理 Javascript
的 V8
引擎,那什麼是 V8
引擎呢?它實際上就包含了對 Javascript
解析(parse) 與 編譯(compile) 的處理
圖片來源:https://dev.to/edisonpappi/how-javascript-engines-chrome-v8-works-50if
JS 檔案 (source code),雖然人類看得懂但對於電腦來說就像是天書一樣,所以 JS 檔案 需要轉換為機器看得懂的機器碼,而這個轉換的過程就是中間這一塊 Javasciprt 引擎 處理的範疇,而引擎處理的事情大致上來說可以分成三個步驟:
Step 1. 解析(parse) 原始碼結構
Step 2. 轉換為 AST
Step 3. 交由 解釋器(Interpreter) 及 編譯器(Compiler),最終變為可執行的機器碼
我想這裡面每個步驟都牽涉到蠻複雜的知識,所以我找到一些不錯的網站希望分享給大家:
概略說明各個步驟的作用,初步暸解 V8 引擎 - 深入研究 JavaScript 引擎 - (Chrome V8)
解釋 parse => AST 這段的過程 - How JavaScript works: Optimizing for parsing efficiency
用簡單易懂的方式講解什麼是 AST - 淺談 AST 及 ESlint Rule:AST 是殺毀?(上)
清楚易懂的實例,講解 Interpreter 到 Compiler 這段過程的原理 - JavaScript 编译 - JIT (just-in-time) compiler 是怎么工作的