Angular v8 釋出!來看看有什麼新功能

前端先鋒發表於2019-05-31

翻譯:瘋狂的技術宅

原文:jaxenter.com/whats-new-a…

未經允許嚴禁轉載

Angular

Angular 8 終於來了,包括 Ivy 的預覽、service worker 支援,差異化載入以及一些錦上添花的東西。 Manfred Steyer 解釋了最新 Angular 版本中最重要的變化。

Angular 8 剛剛釋出!

完全按照計劃,沒有任何意外:框架和 CLI 的更新可以通過 ng update 完成,其新功能是一個受歡迎的補充,符合“演化而不是”的座右銘。

在本文中,我將介紹 Angular 8 和 Angular CLI 8 的最重要的新功能。我在文中的例子可以在 GitHub 上找到。

先瞅一眼 Ivy

Ivy 是 Angular 世界下一個望眼欲穿的大新聞,它是新的 Angular 編譯器,也是新的渲染管道。Ivy 有可能產生相當小 bundle,它使漸進式編譯更容易,也是 Angular 領域未來創新的基礎。

由於 Angular 大量的底層部分已經為此進行了更改,因此 Angular 團隊特別注意與以前的 Angular 版本的相容性:在切換到 Ivy

之後,現有的程式應該能夠像以前一樣工作。在一切正常的前提下,能夠得到明顯更小的 bundles 應該就足夠了。 這並非是他們dafa善心,而是因為 Google 有 600 多個以 Angular 為基礎的應用程式 —— 儘管是謠傳,但實際數字要高得多。

在 Angular 8 中 Ivy 的預覽版現在可供測試。此版本的目標是獲得早期反饋。因此,Angular 團隊建議不要把 Ivy 用於生產環境,而是繼續使用經典檢視引擎(圖1)。

使用與不使用 Ivy 時的 hello world 程式的 Bundle 大小(來源:由Brad Green和Igor Minar撰寫的 ngconf 2019 主題演講)

使用與不使用 Ivy 時的 hello world 程式的 Bundle 大小(來源:由Brad Green和Igor Minar撰寫的 ngconf 2019 主題演講)

感謝差異載入(如下所示),bundle 大小已經可以立即得到優化。

正如 Google Angular 團隊背後的技術總監 Brad Green 在 ngconf 2019 中提到的那樣,Ivy 將在相容模式下結合差異載入,顯著改善 bundle 的尺寸。尋求刺激的人可以嘗試一下未來的 Ivy API。該模式下有非常大的優化潛力。目前這些 API 仍然被標記為私有。你可以通過檢視它的類和函式來進行判斷:它們以特殊字元 ɵ 開頭。

如果你想嘗試 Ivy,可以通過 enable-ivy 開關生成一個新專案:

ng new ivy-project --enable-ivy
複製程式碼

這樣做的結果是 CLI 會在 tsconfig.app.json 中儲存以下配置條目:

"angularCompilerOptions": { 
        "enableIvy": true 
}
複製程式碼

在更新到 Angular 8 之後,也可以手動新增此條目,以便用 Ivy 測試現有程式。

要在除錯模式下執行程式,建議使用 AOT:

ng serve --aot
複製程式碼

此外,值得一提的是通過 ng build 建立的程式的大小。等到 Angular 9 釋出時 Ivy 最終應該會預設啟用。在此之前,Angular 團隊計劃採取進一步措施以確保與舊版本的相容性。

Web worker

根據定義,JavaScript 是單執行緒的。因此,對於資料呼叫等較大任務非同步處理是很常見的。不用說,這對計算密集型沒有幫助。特別是那些廣泛的 JavaScript 解決方案變得越來越普遍,這就是為什麼現在幾乎所有的瀏覽器都支援支援 Web worker。它們是瀏覽器在自己的執行緒中執行的指令碼。通過傳送訊息與瀏覽器選項卡中的執行緒進行通訊。

雖然 Web worker 本身與 Angular 無關,但在構建過程中必須考慮它們。目標是為每個 Web worker 提供一個 bundle 包。此任務由新的 Angular CLI 完成。

為了說明這個新功能,我將通過實現所謂的 “n 皇后問題”的 JavaScript 進行說明。這個想法是在棋盤上每行放一個皇后,而不能相互公雞。這意味著在同一行、列或對角線中不能有其他皇后。

n皇后問題的一種解決方案

n 皇后問題的一種解決方案

計算棋盤上所有可能的解決方案的演算法被認為是計算密集型的。雖然對有 8 行和 8 列的常規棋盤的計算相當快,但是普通計算機從 12×12 格開始就達到了其極限。當前最高記錄是解決具有 27 x 27 格的解決方案。俄羅斯的超級計算機完成了此任務。

為了將類似這樣的計算甩給後臺,我們必須首先用 Angular CLI 建立 一個Web worker:

ng generate worker n-queens
複製程式碼

此語句不僅為 worker 建立檔案,還為構建過程和現有檔案中的條目建立配置檔案。如果同一資料夾包含具有公共副檔名 .component.ts 的同名元件,則 CLI 甚至會使用與 Web worker 通訊的程式碼對其進行豐富。

worker本身只包含 message 事件的事件監聽器:

import nQueens from './n-queens';

addEventListener('message', ({ data }) => {
  const result = nQueens(data.count);
  postMessage(result, undefined);
});
複製程式碼

當主執行緒向 worker 傳送訊息時會執行該事件。該引數包含從主執行緒發來的資訊。在當前的情況下,它僅限於屬性 count ,它宣告瞭棋盤大小。在計算函式 nQueens 之後,事件監聽器通過 postMessage 將結果傳送回主執行緒。*因此,瀏覽器在那裡觸發 message 事件。

Worker 類被應用於 using 元件來與此 worker 指令碼互動:

const count = parseInt(this.count, 10);

const worker = new Worker('../logic/n-queens.worker', {
    type: 'module' // Worker uses EcmaScript modules
});

worker.postMessage({count});

worker.addEventListener('message', (event) => {
  // tslint:disable-next-line: no-console
  console.debug('worker result', event.data);

  // Update chessboard
  this.processResult(event.data);
});
複製程式碼

元件通過 postMessage 向 worker 傳送帶有所需棋盤大小的訊息,從而觸發計算。它通過訊息事件接收結果。

最後 CLI 負責將工作指令碼正確的轉換和捆綁。由此啟動的 TypeScript 編譯器會通過它們的字尾 .worker.ts 來識別它們,它們在由 ng generate worker 生成的 tsconfig.worker.json 中註冊。為了確保 CLI 在翻譯和捆綁主程式時不再考慮這些檔案,ng generate worker 將相同的檔案模式放在 tsconfig.app.jsonexclude 部分中。

完整的實現包含在作者的樣本集[1]中。為了便於說明,可以在主執行緒和 Web worker 中解決可用的 n 皇后問題。例如,當你為 12 x 12 棋盤請求解決方案時,你將看到 UI 在第一種情況下會被凍結,而 worker 的後臺計算不會降低 UI 的可操作性。

差異載入

目前將程式編譯成舊 ECMAScript 5 程式碼仍然是很常見的,因為“古老的 JavaScript ”在今天仍然在到處執行。這意味著 IE 11 和 Google 搜尋引擎後面的網路爬蟲都可以執行這些程式碼。

但是,新的 ECMAScript 2015 及其後續版本更加高效:這些版本允許更緊湊的 bundle 包,瀏覽器也可以更有效地解釋它們。

從版本 8 開始,CLI 包含一個名為差異載入的功能。其背後的想法是提供兩組 bundle:一組基於 ECMAScript 5 並且針對較舊的瀏覽器,另一組基於較新的 ECMAScript 版本,例如 ECMAScript 2015,以此為現代瀏覽器提供上述優勢。

要啟用差異載入,你不用做太多的事情:只需要為 ECMAScript 版本設定一個上限和下限。在 tsconfig.json 中輸入版本上限,如下所示:

"target": "es2015"
複製程式碼

另一方面,下限由瀏覽器列表來定義。根據市場份額等特定標準,它是一個用來標識許多支援的瀏覽器的檔案。它們可以儲存在例如 browserslist 檔案中,CLI 在生成新專案時同時會在 projectroot 中建立:

> 0.5%
last 2 versions
Firefox ESR
not dead
IE 9-11
複製程式碼

如下圖所示,browserslist 指向 ECMAScript 5 瀏覽器,條目為 IE 9-11。因此,CLI 將下限確定為此版本。如果 CLI 收到構建( ng build)指令,則將對兩個版本進行編譯和 bundling 過程:

構建差異載入

構建差異載入

這個過程的缺點顯而易見:構建過程所需的時間加倍。

為了使不同的瀏覽器可以決定要載入哪個版本的 bundle 包,他們在 index.html 新增中接受 script 的引用:指向 ECMAScript 5 包的那些引用會新增 nomodule。這可以使支援 ECMAScript 2015 及更新版本的瀏覽器忽略這些引用。另一方面,ECMAScript 2015+ bundle 包由 CLI 通過 type ="module" 實現。因此舊版瀏覽器將忽略這些指令碼標記:

<script src="main-es2015.js" type="module"></script>

<script src="main-es5.js" nomodule></script>
複製程式碼

ng build 相比,其他所有 CLI 命令僅使用上限。在上圖中所示的這種情況下,是 ECMAScript 2015。出於效率原因,會發生這種情況:特別是在除錯和測試期間,開發人員希望儘快看到結果,而不需要等待第二次構建。

延遲載入

自 Angular 出現的第一天起,路由就支援延遲載入。到目前為止,這是通過識別載入模組的魔術值來完成的:

{
    path: 'lazy',
    loadChildren: () => './lazy/lazy.module#LayzModule'
}
複製程式碼

“#”號之前的值表示通向模組實現的檔案的路徑;之後的值代表其中包含的類。這種寫作風格也適用於 Angular 8,但是已經被棄用了,現在支援動態 ECMAScript 匯入:

{
    path: 'lazy',
    loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
}
複製程式碼

新的書寫風格中仍然包含檔名作為魔術值。但是由於許多IDE支援匯入,因此無效值將立即返回錯誤。

ViewChild 和 ContentChild 中的重大變化

ViewChildContentChild 的使用方式發生了重大變化,但遺憾的是,過去並不總是表現出一致的行為。雖然它們在早期版本中被用於元件請求不在結構指令內的元素,如 ngIfngFor,但查詢結果已在 ngOnInit 中可用。否則,程式程式碼或過早的可以在 ngAfterViewInit(或 ngAfterContentInit for ContentChild )中訪問它。對於以後因資料繫結而僅載入到 DOM 中的元素,程式程式碼必須分別插入 ngAfterViewCheckedngAfterContentChecked

由於這種行為十分令人困惑,所以現在元件必須指定何時應該進行解決:

@ViewChild('info', { static: false })
  paragraph: ElementRef;
複製程式碼

如果 static 的值為 true,則 Angular 會在初始化元件時嘗試查詢該元素。這隻在不在結構指令中時才有效。使用 static:false 時,在啟動或重新整理檢視後進行解析。

ng update 命令 會自動嘗試在此處輸入正確的值。如果無法做到這一點,則會在其位置新增帶有 TODO 的註釋。

與相關裝飾器 ViewChildrenContentChildren 的查詢不受此更改的影響。他們總是表現出 static:false 意義上的動態行為。

ngUpgrade的新功能

到目前為止,AngularJS 1.x 和 Angular 與 ngUpgrade 的混合操作中存在的一個問題是:兩個框架的路由有時一直在爭奪 URL。這導致了難以理解的副作用。為了避免這種情況,可以使用相同的 Location 服務去訪問兩個版本框架中的 URL 。

為實現這一目標,Angular 團隊擴充套件了Angular Location 服務的可能性,從而為 AngularJS 中的 $location 提供了替代。

出於這個原因,在 Location 服務中新增了用於監視URL更改的新方法 onUrlChange 以及其他修改:

export class AppComponent {
  constructor(loc: Location, pLoc: PlatformLocation) {
    loc.onUrlChange((url) => console.debug('url change', url));
    console.debug('hostname: ', pLoc.hostname);
  }
}
複製程式碼

PlatformLocation 服務提供對 URL 各個部分的附加訪問。有關如何使用 $location 替換的詳細描述(用於更好地交織兩個框架)可以在這裡找到。此外,你現在可以找到延遲載入 AngularJS 的想法,它基於前面提到的動態 ECMAScript 匯入。

結論

Angular團隊再次表達了自己的觀點:遷移到新的 Angular 版本很容易,並且不需要進行大的更改。使得使用 Google 的 SPA 框架更加舒適。如果舊版瀏覽器不受支援或不支援單獨的 bundle 包,則差異載入會為進一步優化 bundles 包。 Web worker 支援表明越來越多的計算密集型任務開始進入瀏覽器。現在可以嘗試用 Ivy 邁出第一步。

歡迎關注前端公眾號:前端先鋒,獲取前端工程化實用工具包。

Angular v8 釋出!來看看有什麼新功能

相關文章