依赖注入和提供者配置

作为Angular开发人员,我们经常使用和创建服务。所以,在今天的文章中,让我们揭开下面语法的神秘面纱,看看它有哪些不同的选项:

当服务为在根注入器中提供providedIn:“根”),这意味着这样的服务可以被注入到应用程序的任何组件中,并且该服务将是应用程序中所有消费者共享的单例服务。

如果要限制服务的范围,可以在模块或者一个组件而不是根注入器。语法是这样的——我们使用目标模块或组件的类名:

当一个模块提供服务时,只有该模块的组件/指令/管道/服务可以注入该服务。然而,当在组件中提供时,该组件和它的孩子可以注入该服务。

从语法的角度来看,提到using也是很重要的providedIn相当于在组件或模块中执行以下操作:

上述代码等价于以下代码:

所以你只需要其中一个;两者都是多余的。

最后,还有另一种选择:平台

该服务可以被注入到当前浏览器选项卡中的任何Angular应用中。这是一个罕见的用例,但如果你在同一个页面上运行多个Angular应用程序,并且想在这些应用程序之间共享服务,平台是你需要的。

欲了解更多信息,请阅读我的那篇文章涵盖了所有这些选项(注意:providedIn:“任何”以前是一个选项,但现在已弃用,这就是为什么我没有提到它)

如何决定使用哪个RxJs操作符?

有很多RxJs中有120个操作符,有这么多的选择,决定我们应该使用哪一个可能是一个挑战。我们讲了很少有在本时事通讯中迄今为止提到的网站如Rxmarbles来了解更多关于这些操作符的信息

幸运的是,Rxjs.dev有一个有趣的功能叫做算子决策树.这个工具会询问一些关于我们正在尝试做什么的问题,并最终建议一个可以满足需求的操作符。

它使用向导式的方法:

该工具非常出色,并且确实节省了大量时间来研究文档中的操作符。我发现在一些场景中,它会建议废弃的选项。不过,每个已弃用的特性都有一个指向其替代品的链接,因此很容易从那里找到要使用的实际操作符。

Angular Signals正在开发中!

这可能是自多年前Angular v2发布以来,框架中最重要的变化。

一个新功能叫做信号正在用Angular进行原型化,以及我们可以在GitHub上跟踪整个讨论

信号从何而来?

它们是Angular团队多年来对来自开发者社区的几个不同请求的回答,更具体地说:

  • 能够使用观察对象@Input
  • 能够在不使用Zone.js的情况下使用Angular来更好地控制变更检测。
  • 将状态管理内置在框架中,这样我们就不再需要NgRx或NgXs这样的库了。
  • 能够以响应式的方式使用Angular,而不依赖于RxJs。

换句话说,信号将是一个清晰统一的模型,用于说明数据如何在应用程序中流动,并且不需要任何依赖项(不需要RxJs、Zone或其他第三方库)。

我们需要改变应用程序中的所有内容吗?

不,因为Angular团队已经沟通过了:

  • 信号将是可选的,目前使用Angular的方式将保持不变。
  • 信号将提供一些方法来很好地使用RxJs(一个信号可以变成一个可观察对象,反之亦然)

信号会是什么样子?

现在得出确切的API还为时过早。我们不能100%确定信号是什么样的,但早期的API原型是这样的:

创建一个具有默认值的信号(本例中为0)

上面的代码行将非常类似于这样做const counter = new行为主体(0);

为信号设置一个新值

更新从当前值派生的值

更新信号中的值(内部状态的突变)

在HTML模板或Typescript代码中显示信号的值

上面的等价于计数器|异步当使用RxJs时。好在有了信号系统,就不会再有了.subscribe ()而且.unsubscribe ()

如果你想深入了解更多细节,这里是当前原型的文档.再说一次,这还处于早期阶段,我不指望信号在Angular 17或18之前完全可用,但这还是非常令人兴奋的!

图像优化指令- NgOptimizedImage

Angular团队一直专注于改进框架,让一切变得更快,从编译器到我们的运行时代码,都得到了优化、最小化和摇树。

图像优化指令被添加到角15本着同样的精神。

它的作用:

  • 智能延迟加载:用户在页面加载时不可见的图像稍后会在用户向下滚动到该页面部分时加载。
  • 关键图像的优先级:首先加载基本图像(例如标题横幅)
  • 针对流行映像工具的优化配置:如果你使用的是CDN,该指令将自动从CDN中选择适当的图像大小,根据图像将显示在屏幕上的像素数优化下载大小。
  • 内置错误和警告:除了上述内置优化之外,该指令还具有内置检查,以确保开发人员在图像标记中遵循了推荐的最佳实践。

你所要做的就是使用ngSrc属性,而不仅仅是src

对于CDN优化,您可以使用其中之一现有4家供应商(或创建自己的),以便始终要求适当的图像大小。在我的例子,我使用Imgix所以我的配置看起来像这样:

仅从这些信息中,我们就可以知道Angular能够生成适当的图像url来获取尽可能小的图像来适合我们的div——如果你需要的只是200 x 100像素的图像,就不用再下载2000 x 1000像素的图像了:

NgOptimizedImage指令的一部分@angular /常见模块,就像ngFor而且ngIf,所以如果你使用这些指令,它已经是你工具箱的一部分了。

它也可以用作独立的指令没有进口CommonModule.我的例子是在斯塔克布利茨.的官方文档以及更多关于这个指令可以在这里找到

独立应用程序和路由器配置

通过这篇每日发布的文章,让我们回到Angular新的独立特性。到目前为止,我们已经看到了如何创建独立组件,添加依赖关系,延迟加载独立组件。

因为独立组件的主要目标是拥有更少的NgModules,那么创建一个带有no的Angular应用程序呢NgModule吗?

进入bootstrapApplication函数(从@angular / platform-browser).它所需要的只是根独立AppComponent作为参数:

就是这样。没有AppModule需要的。现在你可能想知道:如何添加一些路由器配置?

有一个provideRouter这个函数,还有几个路由器实用功能配置预加载,保护,错误处理,和更多的

最后,如果你需要使用来自第三方模块的服务,并且不想导入该模块的其他特性(组件/管道/指令),你还可以执行以下操作:

正如你所看到的,独立组件已经为许多新的基于函数的特性(而不是类/服务)铺平了道路,我们将在接下来的文章中看到更多这样的特性。

Angular 15.2有什么新特性?

Angular 15.2在几天前发布了。这个版本新增的主要功能是一个新的Angular CLI原理图,用于将你现有的代码迁移到独立的组件上:

              
              
Ng生成@angular/core:独立的

这个原理图还没有被记录在Angular的网站上,因为它还处于早期阶段。到目前为止,它似乎有三个选择:

  • convert-to-standalone:默认选项。将所有组件转换为独立的组件,除了在main中声明的组件AppModule
  • prune-ng-modules:删除所有不再需要的模块,因为它们的特性已经迁移到独立组件。
  • standalone-bootstrap属性引导应用程序bootstrapApplication函数中引用的组件AppModule

随着这个新示意图的发展,我将在简报中发布更多信息。

另一个更新是基于类的守卫被弃用了,这意味着Angular团队正在推动新的基于功能的路由器特性

最后,一个新的RouterTestingHarness添加了实用程序来帮助路由器加载的单元测试组件。Angular团队发布了一个简短的指南解释如何使用它

RxJs主题:什么时候,为什么?

我们本周的RxJs主题是Subjects。Angular有多个服务和类(比如FormControl),让我们可以访问我们可以订阅的可观察对象。但如果我们想创建自己的Observable发射数据?

当有一个可观察到的构造函数和可观察的创建函数,如而且,这些解决方案都不如使用主题

为什么呢?因为实验对象为我们检查了很多框:

  • 它们是多播的,这意味着它们支持开箱即用的多个订阅者(Observable默认不支持)。
  • 它们可以重放值给新订阅者(BehaviorSubject而且ReplaySubject这样做)

在构建Angular应用时,这两个特性非常关键,因为我们的数据通常由服务处理,然后由组件使用。例如,假设一个服务获取一些数据(例如,登录时的用户会话信息)。在这种情况下,稍后将在屏幕上显示的组件必须订阅该信息并立即获得当前会话信息(这就是为什么重玩性/缓存最新值非常重要)。

另外,Subject API非常简单:

所以我们可以完全控制我们排放什么,何时以及如何排放。所有这些都有一个方法:. next ()

既然主题是具体类型的吗可观测的,你可以用同样的方式订阅:subject.subscribe ().也就是说,将主题作为对象公开是一种最佳实践可观测的通过使用asObservable ()方法如下所示:

有关如何使用主题以及不同类型的主题的更多详细信息,请访问我的RxJs主题教程

惰性加载独立组件

现在我们两个都讲了独立的组件而且惰性加载Angular模块,我们可以引入的概念延迟加载独立组件,这在Angular 14之前是不可能的。

从语法的角度来看,唯一的区别是我们使用loadComponent而不是loadChildren.在路由配置方面,其他一切保持不变:

现在,延迟加载模块的好处之一是它可以有自己的路由配置一次为不同的路由惰性加载多个组件

好消息是,我们还可以惰性加载多个独立组件。它所需要的只是创建一个指定的路由文件loadChildren像这样:

今天要分享的最后一件很酷的事情是:除了上面的语法,Angular现在还支持Typescript中的默认导出loadChildren而且loadComponent

这意味着前面的详细语法:

loadComponent: () => import('./admin/panel.component').then(mod => mod. adminpanelcomponent)},

现在可以变成:

loadComponent: () => import('./admin/panel.component')

如果该组件是其文件中的默认导出,则此方法有效,这意味着类声明看起来像这样:

导出默认类PanelComponent

这同样适用于loadChildren如果路由数组(或NgModule)是其文件中的默认导出。你可以看到斯塔克布利茨的例子

延迟加载以获得更好的Angular性能

在我们继续关于独立组件的系列文章之前,有必要先讨论一下创建高性能Angular应用的最重要工具:延迟加载

当我们使用惰性加载时,我们不是将我们的应用程序构建为一个单独的代码包,当用户在浏览器中访问应用程序时就会下载,而是将我们的代码分成几个不同的部分,然后下载在需要时按需提供

例如,在没有延迟加载的情况下,如果我们的应用程序Javascript代码有25mb大,那么浏览器必须下载、解析和运行这25mb的代码,这可能会大大降低移动设备或internet连接的速度。

相反,我们可以将应用程序划分为不同的模块包含组件、管道、指令和服务。在我们的例子中,让我们假设创建一个AdminModule其中包括应用程序Admin部分所需的所有功能。如果这个模块最终包含10mb的代码,并且我们对它使用惰性加载,那么应用程序的初始包将从25mb下降到15mb,这是一个很大的差异。

只有管理员用户必须下载管理部分的10mb代码,这对性能和安全性都很好(黑客无法对从未在他们的浏览器中下载过的代码进行逆向工程)。

惰性加载最好的部分是在我们的路由器配置中使用一行代码启动它:

上面的代码行会让Angular编译器自动创建一个代码包AdminModule并启用延迟加载该代码时/项目访问。就是这样!