Angular v8 發佈!來看看有什麼新功能[每日前端夜話0x7A]
瘋狂的技術宅 前端先鋒
每日前端夜話0x7A
每日前端夜話,陪你聊前端。
每天晚上18:00準時推送。
正文共:3332 字
預計閱讀時間: 8 分鐘
翻譯:瘋狂的技術宅
來源:jaxenter
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 應該就足夠了。這並非是他們大發善心,而是因爲 Google 有 600 多個以 Angular 爲基礎的應用程序 —— 儘管是謠傳,但實際數字要高得多。
在 Angular 8 中 Ivy 的預覽版現在可供測試。此版本的目標是獲得早期反饋。因此,Angular 團隊建議不要把 Ivy 用於生產環境,而是繼續使用經典視圖引擎(圖1)。
使用與不使用 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 開關生成一個新項目:
1ng new ivy-project --enable-ivy
這樣做的結果是 CLI 會在 tsconfig.app.json 中存儲以下配置條目:
1"angularCompilerOptions": {
2 "enableIvy": true
3}
在更新到 Angular 8 之後,也可以手動添加此條目,以便用 Ivy 測試現有程序。
要在調試模式下運行程序,建議使用 AOT:
1ng 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皇后問題的一種解決方案
計算棋盤上所有可能的解決方案的算法被認爲是計算密集型的。雖然對有 8 行和 8 列的常規棋盤的計算相當快,但是普通計算機從 12×12 格開始就達到了其極限。當前最高記錄是解決具有 27 x 27 格的解決方案。俄羅斯的超級計算機完成了此任務。
爲了將類似這樣的計算甩給後臺,我們必須首先用 Angular CLI 創建 一個Web worker:
1ng generate worker n-queens
此語句不僅爲 worker 創建文件,還爲構建過程和現有文件中的條目創建配置文件。如果同一文件夾包含具有公共文件擴展名 .component.ts 的同名組件,則 CLI 甚至會使用與 Web worker 通信的代碼對其進行豐富。
worker本身只包含 message 事件的事件監聽器:
1import nQueens from './n-queens';
2
3addEventListener('message', ({ data }) => {
4 const result = nQueens(data.count);
5 postMessage(result, undefined);
6});
當主線程向 worker 發送消息時會執行該事件。該參數包含從主線程發來的信息。在當前的情況下,它僅限於屬性 count ,它聲明瞭棋盤大小。在計算函數 nQueens 之後,事件監聽器通過 postMessage 將結果發送回主線程。*因此,瀏覽器在那裏觸發 message 事件。
Worker 類被應用於 using 組件來與此 worker 腳本交互:
1const count = parseInt(this.count, 10);
2
3const worker = new Worker('../logic/n-queens.worker', {
4 type: 'module' // Worker uses EcmaScript modules
5});
6
7worker.postMessage({count});
8
9worker.addEventListener('message', (event) => {
10 // tslint:disable-next-line: no-console
11 console.debug('worker result', event.data);
12
13 // Update chessboard
14 this.proce***esult(event.data);
15});
組件通過 postMessage 向 worker 發送帶有所需棋盤大小的消息,從而觸發計算。它通過消息事件接收結果。
最後 CLI 負責將工作腳本正確的轉換和捆綁。由此啓動的 TypeScript 編譯器會通過它們的後綴 .worker.ts 來識別它們,它們在由 ng generate worker 生成的 tsconfig.worker.json 中註冊。爲了確保 CLI 在翻譯和捆綁主程序時不再考慮這些文件,ng generate worker 將相同的文件模式放在 tsconfig.app.json 的 exclude 部分中。
完整的實現包含在作者的樣本集[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 中輸入版本上限,如下所示:
1"target": "es2015"
另一方面,下限由瀏覽器列表來定義。根據市場份額等特定標準,它是一個用來標識許多支持的瀏覽器的文件。它們可以存儲在例如 browserslist 文件中,CLI 在生成新項目時同時會在 projectroot 中創建:
1> 0.5%
2last 2 versions
3Firefox ESR
4not dead
5IE 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" 實現。因此舊版瀏覽器將忽略這些腳本標記:
1<script src="main-es2015.js" type="module"></script>
2
3<script src="main-es5.js" nomodule></script>
與 ng build 相比,其他所有 CLI 命令僅使用上限。在上圖中所示的這種情況下,是 ECMAScript 2015。出於效率原因,會發生這種情況:特別是在調試和測試期間,開發人員希望儘快看到結果,而不需要等待第二次構建。
延遲加載
自 Angular 出現的第一天起,路由就支持延遲加載。到目前爲止,這是通過識別加載模塊的魔術值來完成的:
1{
2 path: 'lazy',
3 loadChildren: () => './lazy/lazy.module#LayzModule'
4}
“#”號之前的值表示通向模塊實現的文件的路徑;之後的值代表其中包含的類。這種寫作風格也適用於 Angular 8,但是已經被棄用了,現在支持動態 ECMAScript 導入:
1{
2 path: 'lazy',
3 loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
4}
新的書寫風格中仍然包含文件名作爲魔術值。但是由於許多IDE支持導入,因此無效值將立即返回錯誤。
ViewChild 和 ContentChild 中的重大變化
ViewChild 和 ContentChild 的使用方式發生了重大變化,但遺憾的是,過去並不總是表現出一致的行爲。雖然它們在早期版本中被用於組件請求不在結構指令內的元素,如 ngIf 或 ngFor,但查詢結果已在 ngOnInit 中可用。否則,程序代碼或過早的可以在 ngAfterViewInit(或 ngAfterContentInit for ContentChild )中訪問它。對於以後因數據綁定而僅加載到 DOM 中的元素,程序代碼必須分別插入 ngAfterViewChecked 或 ngAfterContentChecked。
由於這種行爲十分令人困惑,所以現在組件必須指定何時應該進行解決:
1@ViewChild('info', { static: false })
2 paragraph: ElementRef;
如果 static 的值爲 true,則 Angular 會在初始化組件時嘗試查找該元素。這隻在不在結構指令中時纔有效。使用 static:false 時,在啓動或刷新視圖後進行解析。
ng update 命令 會自動嘗試在此處輸入正確的值。如果無法做到這一點,則會在其位置添加帶有 TODO 的註釋。
與相關裝飾器 ViewChildren 和 ContentChildren 的查詢不受此更改的影響。他們總是表現出 static:false 意義上的動態行爲。
ngUpgrade的新功能
到目前爲止,AngularJS 1.x 和 Angular 與 ngUpgrade 的混合操作中存在的一個問題是:兩個框架的路由有時一直在爭奪 URL。這導致了難以理解的副作用。爲了避免這種情況,可以使用相同的 Location 服務去訪問兩個版本框架中的 URL 。
爲實現這一目標,Angular 團隊擴展了Angular Location 服務的可能性,從而爲 AngularJS 中的 $location 提供了替代。
出於這個原因,在 Location 服務中添加了用於監視URL更改的新方法 onUrlChange 以及其他修改:
1export class AppComponent {
2 constructor(loc: Location, pLoc: PlatformLocation) {
3 loc.onUrlChange((url) => console.debug('url change', url));
4 console.debug('hostname: ', pLoc.hostname);
5 }
6}
PlatformLocation 服務提供對 URL 各個部分的附加訪問。有關如何使用 $location 替換的詳細描述(用於更好地交織兩個框架)可以在這裏找到。此外,你現在可以找到延遲加載 AngularJS 的想法,它基於前面提到的動態 ECMAScript 導入。
結論
Angular團隊再次表達了自己的觀點:遷移到新的 Angular 版本很容易,並且不需要進行大的更改。使得使用 Google 的 SPA 框架更加舒適。如果舊版瀏覽器不受支持或不支持單獨的 bundle 包,則差異加載會爲進一步優化 bundles 包。 Web worker 支持表明越來越多的計算密集型任務開始進入瀏覽器。現在可以嘗試用 Ivy 邁出第一步。