Ahead-of-Time (AOT)編譯
在Angular 2 中有兩種編譯模式:
- JIT(Just-in-Time):Angular預設是使用 Just-in-Time (JIT) 即時編譯,等瀏覽器下載完 *.js 檔案後,會在用戶端的瀏覽器編譯 Angular 的 JS 程式碼,接著才會渲染畫面。
- AOT(Ahead-of-Time):在程式發佈之前就透過 Angular Compiler 進行編譯,所以瀏覽器下載完的 *.js 檔案,就可以直接被執行,然後渲染畫面。
下表為這兩種佈署方式的簡單比較表:
Characteristic | JiT | AoT |
---|---|---|
Compilation target | Browser | Server |
Compilation context | Runtime | Build |
Bundle size | Huge (~1.2 MB) | Smaller (~400 KB) |
Execution Performance | – | Better |
Startup time | – | Shorter |
AoT的要點是將編譯從運行時移動到構建過程。因此我們不需要讓用戶載入完整的編譯器功能,也不需要在用戶端才去做編譯的動作,所以從對照表可以看出,這個動作可以讓效能以及檔案大小都變得更好。
另外,預先編譯可以在編譯期就發現一些模版的錯誤,而不需要等到實際在客戶端執行才發現。使用AOT,編譯器僅僅使用一組庫在構建期間運行一次;使用JIT,編譯器在每個用戶的每次運行期間都要用不同的庫運行一次。
AOT編譯的優點
- 更快:瀏覽器直接載入可運行的程式碼,可以立即使用,而不用等待編譯完成。
- 減少HTTP異部請求:編譯器把外部HTML模板和CSS樣式表內聯到了該應用的JavaScript中。消除了用來下載那些源文件的Ajax請求。
- 檔案更小:客戶端不用載入完整的Angular編譯器
- 提早檢測模板錯誤:編譯時會跳出模板綁定錯誤警告,提早發現錯誤
- 更安全:AOT編譯遠在HTML模版和組件被服務到客戶端之前,將它們編譯到JavaScript文件。沒有模版可以閱讀,沒有高風險客戶端HTML或JavaScript可利用,所以注入攻擊的機會較少。
使用AOT編譯
Angular5大大的簡化了AOT流程,我們只需在生成文件時加上--aot
ng build –aot
ng serve –aot
如果我們使用--prod
預設也會是aot輸出。
用AOT編譯的程式編寫限制
如果使用AOT預編譯,在撰寫angular的metadata要注意下面幾點:
不支援function expression
var myFunction = function [name]([param1[, param2[, ..., paramN]]]) { statements };
不支援Arrow functions
(param1, param2, …, paramN) => { statements }
像下面這種設定方法在AOT是不被支援的
@Component({ ... providers: [{provide: server, useFactory: () => new Server()}] })
需改成這樣:
export function serverFactory() { return new Server(); } @Component({ ... providers: [{provide: server, useFactory: serverFactory}] })
在元數據內單獨使用常數
因為常數是在編譯時就編譯進JS裡,如下面的寫法會造成AOT在編譯時遺失template
常數的值:
const template = '<div>{{hero.name}}</div>'; @Component({ selector: 'app-hero', template: template }) export class HeroComponent { @Input() hero: Hero; }
我們可以改用下面這種寫法
@Component({ selector: 'app-hero', template: '<div>{{hero.name}}</div>' }) export class HeroComponent { @Input() hero: Hero; }
或將常數放至一個運算表達式內:
const template = '<div>{{hero.name}}</div>'; @Component({ selector: 'app-hero', template: template + '<div>{{hero.title}}</div>' }) export class HeroComponent { @Input() hero: Hero; }
裝飾和數據綁定的類成員必須公開
在metadata中只支援下面的angular decorators
DECORATOR | MODULE |
---|---|
Attribute |
@angular/core |
Component |
@angular/core |
ContentChild |
@angular/core |
ContentChildren |
@angular/core |
Directive |
@angular/core |
Host |
@angular/core |
HostBinding |
@angular/core |
HostListener |
@angular/core |
Inject |
@angular/core |
Injectable |
@angular/core |
Input |
@angular/core |
NgModule |
@angular/core |
Optional |
@angular/core |
Output |
@angular/core |
Pipe |
@angular/core |
Self |
@angular/core |
SkipSelf |
@angular/core |
ViewChild |
@angular/core |
如果表達式使用不受支持的語法,則collector將錯誤的項目寫入.metadata.json
文件。如果編譯器需要這段元數據來生成應用程序代碼,則編譯器稍後將報告該錯誤。
若希望能立即顯示錯誤,則可以將tsconfig
的strictMetadataEmit
設為true
“angularCompilerOptions”: {
…
“strictMetadataEmit” : true
}