翻译:疯狂的技术宅原文:https://jaxenter.com/whats-ne...
未经允许严禁转载
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
开关生成一个新项目:
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 皇后问题的一种解决方案
计算棋盘上所有可能的解决方案的算法被认为是计算密集型的。虽然对有 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.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
中输入版本上限,如下所示:
"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 中的重大变化
ViewChild
和 ContentChild
的使用方式发生了重大变化,但遗憾的是,过去并不总是表现出一致的行为。虽然它们在早期版本中被用于组件请求不在结构指令内的元素,如 ngIf 或 ngFor,但查询结果已在 ngOnInit 中可用。否则,程序代码或过早的可以在 ngAfterViewInit(或 ngAfterContentInit for ContentChild )中访问它。对于以后因数据绑定而仅加载到 DOM 中的元素,程序代码必须分别插入 ngAfterViewChecked 或 ngAfterContentChecked。
由于这种行为十分令人困惑,所以现在组件必须指定何时应该进行解决:
@ViewChild('info', { static: false })
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
以及其他修改:
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 迈出第一步。
本文首发微信公众号:前端先锋
欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章
欢迎继续阅读本专栏其它高赞文章:
- 深入理解Shadow DOM v1
- 一步步教你用 WebVR 实现虚拟现实游戏
- 13个帮你提高开发效率的现代CSS框架
- 快速上手BootstrapVue
- JavaScript引擎是如何工作的?从调用栈到Promise你需要知道的一切
- WebSocket实战:在 Node 和 React 之间进行实时通信
- 关于 Git 的 20 个面试题
- 深入解析 Node.js 的 console.log
- Node.js 究竟是什么?
- 30分钟用Node.js构建一个API服务器
- Javascript的对象拷贝
- 程序员30岁前月薪达不到30K,该何去何从
- 14个最好的 JavaScript 数据可视化库
- 8 个给前端的顶级 VS Code 扩展插件
- Node.js 多线程完全指南
- 把HTML转成PDF的4个方案及实现
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。