type
status
date
slug
summary
tags
category
icon
password
毫无疑问,依赖注入(DI)是 Angular 框架中很重要的一部分。简单来说,注入器(Injector)会维护一个关于如何创建依赖的列表,我们可以从注入器获取依赖关系。这些功能始终是借助类的构造函数来实现的。自从 Angular 14 开始,有一个强大的新方案可以替代基于构造函数的 DI,也就是本篇文章的主角 - Inject Function。
什么是 Inject Function
在讲 Inject Function 之前,先来回顾一下传统的基于构造函数的 DI 是怎样使用的。
在传统的用法中,Angular 中的组件、指令或者管道如果需要使用某个服务,必须通过构造函数参数注入才可以使用。
如果这个服务的
Token 不是类而是 InjectionToken,则需要通过 @Inject() 参数装饰器使用:接下来看一下 Inject Function 的写法:
通过代码我们可以看到,如果要在组件中获取依赖,只需要调用
inject 方法,写法大大的简化了,也不需要仅仅为了依赖注入而显式定义构造函数。看到这里大家可能觉得只是写法上简单了一些,别急,让我们来看下一个例子:
在项目开发中,某个 service 依赖另一个 service 是很常见的情况,Angular 给我们提供了一种写法 -
factory provider。当
deps 数组中有多项时,这种写法的缺点就体现出来了,因为 deps 的顺序对应必须对应工厂函数参数的列表,我们需要手动确保顺序。而使用
inject 函数写法如下:这样看起来是不是简化的更多了呢?而且更不易出错。
Inject vs 构造函数
现在我们已经了解了
inject 函数的基本语法,接下来我们列举几个场景,来感受一下基于 inject 写法的优点。继承
Angular 组件是基于 class 的,所以继承在项目开发中很常见。假设我们有一个基类
AnimalComponent:我们的基类依赖于
DataService 服务和 Router。现在有一个子类 CatComponent 需要继承 AnimalComponent,如果子类也有自己的构造函数,则必须把基类的所有依赖通过 super 调用传递过去:当我们大量使用继承或者基类中依赖过多时,会在子类中产生大量无用的模板代码,这是一个很大的缺点。
现在让我们来看一下使用
inject 函数的解决方案:这样子类的构造函数就可以省略掉只为了传递给基类的那些依赖,不需要传递任何参数给
super 调用,也不用关心基类使用了哪些服务。PS: 如果子类不需要任何依赖,构造函数可以直接省略。
路由守卫
路由守卫是 Angular 中一个很重要的功能,可以让用户在访问某些路由之前检查是否满足条件。我们以最常用的
canActivate 为例。在之前,我们首先需要创建一个类,并且实现
CanActivate 接口,然后把这个类放到对应的路由配置中。这会产生很多的样板文件代码,实际上核心的逻辑就那么一行。甚至哪怕你的守卫没有任何依赖项,也必须编写一个 Injectable 类。作为一名追求效率的开发人员,肯定希望减少这种无用的代码。
那接下来看一下使用函数式守卫 +
inject 函数的解决方案:我们只需要写一个函数,并且函数中可以使用
inject 获取依赖,省去了被开发者诟病的样板代码。DI functions
普通的 JavaScript 函数在使用
inject 函数之后,我们可以称之为 DI functions。这些函数让 Angular 变得更加灵活,既可以用面向对象的模式组织业务代码,又可以通过函数编写可复用的逻辑。上面代码写了一个简单的可复用的
logToken() 函数,在过去,我们需要把代码放到一个 service 中,之后在组件的构造函数中注入服务,才能实现同样的功能。当然也可以稍微变一下,根据依赖来为组件或服务提供数据:
甚至我们可以结合 Observable,来创造一个定制的 Observable:
总结
与传统的基于构造函数的 DI 相比,
inject 函数是一种更简单的从注入器获取依赖的方法。它不仅简化了常见的场景,而且还可以借助简单的 JavaScript 函数共享可重用逻辑并访问依赖注入系统。需要注意的是,
inject 函数只能用于构造器阶段,这意味着其只能在构造器函数作用域(constructor function scope)和字段初始化器(field initializers)中使用。参考资料
- Author:大胖猫
- URL:http://preview.tangly1024.com/article/223f4632-e87d-8098-b56c-f26b39f4eee1
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!









