Angular 應用主要包含元件和它們的HTML模闆。 在浏覽器可以渲染應用之前,元件和模闆必須要被Angular編譯器轉換為可以執行的JavaScript。最簡單的方式就是将所有代碼加載到浏覽器中,包括我們自己寫的元件的 Angular 編譯器,然後在浏覽器中編譯,這種編譯方式就是 JIT(Just-in-Time).
JIT 編譯與比較大的性能問題。由于需要在浏覽器中執行這個編譯過程,是以視圖需要花更長時間才能渲染出來。而且編譯所需要的 Angular 編譯器和許多應用并不需要的庫也會發送到浏覽器,這導緻應用體積變大,浏覽器加載速度也變慢。
AOT 編譯
AOT(Ahead of Time) 編譯方式會首先在本地将應用編譯完成,是以可以節省在浏覽器上的首次編譯時間,而且編譯完後的應用不再需要 Angular 編譯器了,是以體積也大大縮小了。
使用 AOT 編譯可以在 官方文檔 看到。
當然最簡單的方式是使用 angular-cli
下面看兩種編譯方式的體積大小以及應用加載速度
首先是體積大小,下面主要觀察 vendor.bundle.js 檔案的大小,該檔案中打包了應用所依賴的 node_module 中的庫。
JIT 模式下 vendor.bundle.js 的體積為 3.2M
js加載時間大概為 1.1s
AOT 模式下 vendor.bundle.js 僅為 609K,當然不僅僅是減少了編譯器的體積,還有搖樹優化 (Rollup) 的功勞.
js加載時間大概為0.4s
bundle-analyzer
雖然使用 AOT 編譯之後體積縮小了很多,但是還是有優化的空間。使用 webpack-bundle-analyzer 可視化工具可以分析 webpack 打包後的檔案中所有依賴檔案所占的體積。
使用 npm 安裝
并在 ng build 時輸出統計資料
此時在輸出檔案夾中會多一個 stats.json 檔案,裡面包含了打包後 js 的組成資訊,接下來使用 webpack-bundle-analyzer 分析,
webpack-bundle-analyzer dist/stats.json
可以得到如下圖中類似的結果
可以看到在 node_module 中處理 angular 核心檔案,還有 rxjs 也占了很大一部分體積。但其實 rxjs 包含了很多很多庫函數,而我們的應用中一般隻會用到其中的一部分。如果去掉我們未使用的檔案,那應該會減少一部分體檢。
事實上 rxjs 也提供了按需導入的方法,如果使用下面方法,會将 rxjs 中的所有庫函數都導入進來
import Rx from 'rxjs/Rx';
将導入方法改為
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/empty';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';
按需導入庫函數,再使用webpack-bundle-analyzer
可以看到rxjs所占的體積變小了。整個 bundle 的體積也從 609K 降到了 463K 。
事實上 Angular 官方說體積最小可以達到 250K 左右,當然我這裡因為還導入了其他的庫,例如 marked.js 和 highlight.js。是以體積會更大一點。
惰性加載
當我們自己的應用中功能越來越多的時候,應用的體積也會越來越大。我們可以通過異步加載特性子產品來減少主子產品的體積。
惰性加載 (lazy-load) 方法可以參考文檔中路由導航部分
惰性加載有以下優點:
我們可以隻在使用者請求時才加載某些特性區。
對于那些隻通路應用程式某些區域的使用者,這樣能加快加載速度。
我們可以持續擴充惰性加載特性區的功能,而不用增加初始加載的包體積。
引入惰性加載後, AOT 編譯也會多出相應的 js 檔案。原來的 main.bundle.js 的體積則會相應地減小。
伺服器端渲染
AOT 模式下需要加載的 JS 檔案體積已經大大減少了,加載速度也變快了。
而使用伺服器端渲染可以再提升首屏加載速度,而且對于 SEO 優化也是有利的。
伺服器端渲染方法可以看 Angular Universal 這一章,雖然文檔中還有一些坑(詳細看我的前一篇文章)。
伺服器渲染後需要下載下傳的檔案如下圖,因為此時渲染過程已經在伺服器端完成,是以浏覽器隻要下載下傳 html 檔案就可以了。
加載速度如下圖,可以看到相比前面的家族過程,Scripting 時間大大縮短了,因為不再需要運作 angular 代碼了。
需要注意的是
雖然伺服器端渲染即使不加入 AOT 産生的 js 代碼也可以在浏覽器端看到頁面,但這樣的頁面是靜态的,不再具有 Angular 單頁面應用帶來的優點了。
是以事實上還是需要引入 AOT 産生的 js 代碼,但是這裡引入 js 代碼并不會影響頁面的加載。