2023 年之前 Angular 没那么好
你可能经常听到有人这样说
Angular 会在 3 年后等你。 Angular 更适合大型或企业项目 Angular 提供了出色的更新体验 ……
在这篇文章中,我将向您展示为什么我认为 Angular 在 2023 年之前没那么好。
当然,在将 Angular 与其他框架/库进行比较时,我不能 100% 公平。另外,因为我试图演示 2023 年之前的 Angular 并不是那么好,所以我会过多关注其缺点。这对 Angular 来说不公平。2023 年之后,Angular 变得越来越好,但我将在其他文章中介绍这些部分。
公平起见,我在 2023 年 8 月 15 日创建 2 个项目,1 个用于 Angular,1 个用于 Vue。
对于 Angular,我使用 angular/cli@16.2.0 和ng new my-app-angular
创建。
对于 Vue,我使用 create-vue@3.7.2 和npm create vue@latest
创建。
我将一步步演示它。
创建新项目时
使用 Angular CLI 创建新项目时,我有 2 个选项
-
需要路由
-
CSS格式
使用 Vue CLI 时,
除了2个选项之外,我还有4个以上的选项
- 状态管理库
- e2e测试库
ESLint
Prettier
用于代码格式化- ……
在我看来,对于大型或企业项目而言,在一开始就配置好上述 4 个选项很重要。
如果开发者不是高级或专业前端工程师,或者仅仅想省点事,在 CLI 不默认提供这些选项时,它们很容易丢失。
如果它们没有在一开始被配置好,在开发到一半时,让所有团队成员就一个特定的解决方案达成一致并不容易。有些人喜欢这个状态管理库,而另一些人则喜欢另一个。有些人喜欢分号,有些人不喜欢。如果团队里正好有两个偏好相反又特别坚持的,那么可能就无法统一了。
即使幸运的是,开发者在迭代的过程中重新配置了上述选项,那也依然会有一些遗留代码需要迁移,或者留下了一些不那么好的代码。
考虑到很多人会在提供的选项中直接选择第一个,所以一个完备的脚手架在不知不觉中就统一了不同项目的整体架构和编码风格。以至于开发者随意打开一个 Vue 项目,就可以直接上手,这点在 Vue2 时代尤其明显。
顺便说一句,Angular 到目前为止还没有官方的状态管理解决方案。
由于这个问题, Angular 在 2022 年将状态管理添加到了待办事项中,所以如果你认为 Angular 不需要状态管理库,似乎 Angular 和社区并不同意你的观点。到目前为止,Angular 最受欢迎的状态管理解决方案是ngrx。
实际上,也有很多人通过“RxJs”和“DI”使用自己设计的状态管理库。关于状态管理的选择,虽然不至于像 react 那么繁荣(混乱),但也不容乐观。
默认项目文件夹结构
对于 Angular,在找到CodingStyleGuide章节之前我甚至不知道如何编码。
- 路由器视图放在哪里?
- 共享代码放在哪里?
- ……
而对于 Vue,我认为开发人员几乎可以立即编码。
不管怎样,我将遵循 Angular 风格指南来创建一个heroes
功能模块。
演示代码是从 Angular 主页演示复制的。
这是用户界面:
默认的变更检测策略是性能杀手
您是否注意到当页面加载时该函数在控制台被调用了多少次?6*9=54次! 这是代码
而如果你将鼠标从上到下移动,该功能将被触发299次!
在这种情况下,我们可以使用该OnPush
策略。
isSensitiveHeroName
首次触发9次,事件触发9*9次mouseenter
。
所以通过 OnPush 策略,性能提升了1200% 。实际上,如果我们想将Default
策略更改为OnPush
,我们需要应用更多更改,而不仅仅是此演示中的一行。
对于这种情况,针对 Angular 我们有更好的解决方案。
现在,我们获得了更好的性能,也许是最好的性能。这就是为什么你经常可以在 Angular 社区看到这一点。
永远不要在模板中调用函数
好的。这是我的担忧
避免在模板中使用函数真的好吗?
为了获得更好的性能,我们定义了派生状态isSensitive
。所以,每次我们改变英雄的名字,我们都需要更新isSensitive
。
在实际应用程序中,会有许多派生状态依赖于 2 个或更多其他状态。因此,我们需要添加越来越多的代码来保持当前的性能,这将很快带来错误和维护问题。
可能还有其他方法可以在不编写更多代码的情况下保持性能。但这是我的担忧
Angular 需要开发人员花多长时间才能编写出高性能且易于维护的代码?1个月还是1年?
幸运的是,Angular 于 2023 年推出 Signals ,Signals
目前处于开发者预览版。Signals
允许您编写高性能且易于维护的代码。
复杂的 NgModule
现在,假设我想在 HeroesModule
之外使用HeroListComponent
. 我需要把它从 HeroesModule
导出,然后将其导入到另一个模块(假设AppModule
)。
我只能看到 1 个优点。如果我想使用从 HeroesModule
导出的其他组件,我不需要在AppModule
再次导入组件。
然而,我也看到了很多缺点。
对于开发人员来说,并不知道
AppModule
从HeroesModule
导入了多少东西. 只有 Angular 知道。因为组件必须在模块中声明,所以开发人员不容易知道组件在模块中依赖了多少东西。例如,
HeroListComponent
依赖于CommonModule
和HeroesRoutingModule
吗? 我们需要检查一下。因此,如果您将组件从一个模块移动到另一个模块,但它不起作用,这是很常见的,因为您需要找出该组件需要哪些依赖项并移动依赖项。因为组件中没有声明依赖关系。
总之,组件无法单独工作,如果您来自其他框架,则很难想象这一点。
幸运的是,2022 年底 Angular@15 推出了 standalone
组件。Angular 团队甚至提供了一个工具供您把组件从NgModule
迁移到standalone
。
与 RxJ 的深度绑定
许多 Angular API 使用都需要通过Observable
, 甚至HttpClient
. 然而,对于初学者来说,使用 RxJ 编写代码很容易犯错。
RxJ 声明式风格中需要谨慎的事项
例如,前面HeroListComponent
是用声明式风格实现的。如果我们删除heroes$ | async
模板中的 ,则service.getHeroes
永远不会再次调用 。 如果您是 Angular 或 RxJ 的新手,这可能会让您感到震惊。
另外,如果service.getHeroes
抛出错误一次,该函数将不再工作。这就是为什么您经常可以在声明性代码中看到catchError(() => EMPTY)
。
RxJ 命令式风格中需要谨慎的事项
事实上,许多开发人员正在使用命令式编程。在这种情况下,HeroListComponent
就像
在模板中,heroes$ | async
需要更改为heroes
.
然而,它有缺陷。就像我们需要removeEventListener
一样,我们也需要unsubscribe
或takeUntilDestroyed
。
然而,takeUntilDestroyed
到目前为止,它还处于开发者预览版中。2023 年之前,我们需要添加更多代码。还有一点,这种方式对于OnPush
策略来说并不友好。
简短的结论
正如您所看到的,与 RxJ 的深度绑定使开发人员更容易犯错误或编写容易有内存泄漏的代码。
我确实认为 RxJs 很强大,尤其适合边缘情况。然而,拥有一个强大的工具并不意味着我们在所有情况下都需要使用它。许多没有 RxJ 的框架/库/项目都运行得很好。
另外,我没有提到 RxJs 的学习成本以及它带来的非常具有侵入性的代码风格。
Angular 的现状
正如你所看到的,Angular 带来了许多新的解决方案。这是一件好事,但如果他们不及时指出推荐的解决方案,则可能是一件坏事。社区可能会比以前更加分裂。
- 声明式或命令式编程
- 少或多
RxJs
Default
或者OnPush
NgModule
或者standalone
zone.js
或者Singals
- ……
在这些之间进行选择将导致不同的编码风格,这也会使代码难以维护。
前两个选择已经导致社区分裂。现在我们有更多了。
在我看来,
standalone
+Singals
是 Angular 的未来。- RxJs对于 Angular 来说将会是可选的
。
- 官方的状态管理解决方案也会出现。
- Angular 将更像其他框架/库。
Angular 做出了像选择typescript
这样的伟大选择,但事实证明选择NgModule
和zone.js
可能并不那么成功。即使内置RxJs
API 也可能不是一个好的解决方案。
Angular 并不是在 3 年后等待其他框架/库。
他正在进步和选择。许多框架和开发人员没有选择的一些解决方案通常意味着它们可能不太适合前端开发。在这些情况下,Angular 也在向其他框架/库学习,而不是等待并坚持认为自己的方向是正确的。
实际上,框架/库都是互相学习的。学习和提高自己比认为自己是最好的要好得多。
转载自:https://juejin.cn/post/7271286199167057979