框架依赖注入和普通依赖注入_角服务和依赖注入解释

框架依赖注入和普通依赖注入

服务和喷油器 (Services and Injectors)

Components are responsible for the data that renders into the template. Having external services to draw upon can simplify this responsibility. Plus, encapsulating extraneous is much easier to maintain.

组件负责渲染到模板中的数据。 利用外部服务可以简化此职责。 另外,封装无关的东西更容易维护。

Delegating too many responsibilities onto a single component can complicate the component class. And what if these responsibilities applied to several components? Copying and pasting such logic is extremely poor practice. Any future changes to the logic would be harder to implement and test.

将太多职责委派给单个组件可能会使组件类复杂化。 如果这些责任适用于几个组成部分怎么办? 复制和粘贴这种逻辑是极差的做法。 将来对逻辑所做的任何更改都将更难以实施和测试。

Angular meant to curb this issue with services and dependency injection. Both concepts work together to provide modular functionality.

Angular旨在通过服务和依赖注入来解决此问题。 这两个概念共同作用以提供模块化功能。

Components do not need to provide any extraneous information either. A services imports what it needs to function on behalf of the components it services. The components only need to instantiate the service. From there they service their own needs with the instantiated service instance.

组件也不需要提供任何无关的信息。 服务代表其服务的组件导入功能所需的内容。 组件仅需要实例化服务。 从那里,他们用服务实例化的服务实例自己的需要。

As for testing and future modification, all the logic is in one place. The service instantiates from its source. Tests and modifications to the source apply anywhere the service is injected.

至于测试和将来的修改,所有逻辑都放在一个地方。 该服务从其源实例化。 对源的测试和修改适用于注入服务的任何地方。

服务介绍 (Introduction to Services)

A service is a type of schematic available in Angular. It is generatable by the command-line interface (CLI): ng generate service [name-of-service]. Replace [name-of-service] with a preferable name. The CLI command yields the following.

服务是Angular中可用的一种示意图 。 它可以通过命令行界面(CLI) ng generate service [name-of-service]ng generate service [name-of-service] 。 将[name-of-service]名称[name-of-service]替换为首选名称。 CLI命令产生以下内容。

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class LoggerService {
  constructor() { }
}

The logic of a service is distinct within its class. Angular interprets a class as an injectable service based off the @Injectable decorator. Injectable services must register with an injector.

服务的逻辑在其类中是不同的。 Angular基于@Injectable装饰器将类解释为可注入服务。 注射服务必须在注射器上注册

The component instantiates a service while the injector provides that instance. Keep reading into the next section for more on injectors.

当注入器提供该实例时,该组件实例化服务。 请继续阅读下一部分,以获取有关喷油器的更多信息。

The @Injectable metadata field providedIn: ‘root’ targets the root module of the current application (app.module.ts). It registers the service with the module’s injector so that it can inject that service into any of its children.

@Injectable元数据字段@Injectable providedIn: 'root'用于当前应用程序的根模块( app.module.ts )。 它注册到模块的喷油器的服务,以便它可以注入该服务到任何孩子。

Injectors are the building blocks of Angular’s dependency injection system. Injectors are a good place to focus your attention before continuing with services.

注入器是Angular依赖注入系统的基础。 在继续进行服务之前,喷油器是集中您注意力的好地方。

喷油器 (Injectors)

An application, beginning with app.module.ts, contains a hierarchy of injectors. They exist alongside each module and component in the application tree.

app.module.ts开头的应用程序包含注射器的层次结构。 它们与应用程序树中的每个模块和组件并存。

The green circles indicate injectors. They provide service instances to instantiating components. Depending on which injector a service is registered with, it may or may not be available to a component.

绿色圆圈表示喷射器。 它们提供服务实例来实例化组件。 根据向其注册服务的喷射器,组件可能会或可能无法使用该服务。

Services registered at the root of the app (app.module.ts) are available to all components. An injector for a component may not have a certain service registered. If that is the case and the component requests its instantiation, the injector will defer to its parent. This trend continues until either reaching the root injector or the service is found.

在应用程序的根目录( app.module.ts )注册的服务可用于所有组件。 组件的注射器可能未注册某些服务。 如果是这种情况,并且组件请求其实例化,则注入器将延迟其父对象。 这种趋势一直持续到到达根注入器或找到服务为止。

Looking at the diagram, say that a service registers at point B’s injector. All components at point C and down will not be able to access the service registered at B’s injector. Injectors will never defer to their children for a service instance.

查看该图,假设某个服务在B点的注入器处注册。 C点及以后的所有组件将无法访问在B的喷油器处注册的服务。 注入器永远不会服从其子实例进行服务。

依赖注入 (Dependency Injection)

There are multiple ways to register a service with an application’s injectors.

有多种向应用程序的注入器注册服务的方法。

The providedIn: ‘root’ metadata field of @Injectable provides the most recommended approach. This metadata field released with Angular 6.

@Injectable providedIn: 'root'元数据字段提供了最推荐的方法。 该元数据字段随Angular 6一起发布。

As mentioned before, providedIn: ‘root’ registers a service with the root module injector. It is instantiable across the entire application as a result.

如前所述, providedIn: 'root'向根模块注入器注册服务。 结果,它可在整个应用程序中实例化。

The novelty of providedIn: ‘root’ is tree-shaking. If the service is unused despite its registration, it gets shaken from the application at run-time. That way it does not consume any resources.

ProvideIn的新颖之处在于providedIn: 'root'令人震惊 。 如果该服务,尽管其注册未使用时,它会从在运行时应用动摇 。 这样,它不会消耗任何资源。

The other two ways are more direct and traditional. Granted, they do not offer tree-shaking.

其他两种方式更为直接和传统。 当然,它们不提供摇树。

A service can register with any injector along the component tree. You insert the service as a provider in the @Component metadata field: providers: []. The service is available to the component and its children

服务可以沿着组件树向任何注入器注册。 您将服务作为提供者插入@Component元数据字段中: providers: [] 。 该服务可用于组件及其子组件

In the third registration strategy, the providers: [] metadata exists as its own field in the @NgModule decorator. The service is instantiable from the module to the underlying component tree.

在第三个注册策略中, providers: []元数据作为其自己的字段存在于@NgModule装饰器中。 该服务可从模块实例化到基础组件树。

Remember that unlike with providedIn: ‘root’, @NgModule registration does not offer tree-shaking. Both strategies are otherwise identical. Once a service registers with @NgModule, it consumes resources even if left unused by the application.

请记住,与@NgModule providedIn: 'root'@NgModule注册不提供树状摇动。 两种策略在其他方面都是相同的。 服务使用@NgModule注册@NgModule ,即使应用程序未使用它,它也会消耗资源。

服务继续 (Services Continued)

Writing an actual service comes next. To recap, services handle certain functions on behalf of an application’s components.

接下来是编写实际服务。 概括地说,服务代表应用程序的组件处理某些功能。

Services excel at handling common operations. They spare components the responsibility by doing so. It saves time not having to re-write common operations across multiple components. It is also more testable because the code is in one place. Changes only need to happen in one place without having to search elsewhere.

服务擅长处理常见操作。 通过这样做,他们可以免除组件的责任。 它节省了不必在多个组件之间重写通用操作的时间。 由于代码位于一个位置,因此它也更具可测试性。 更改只需要在一个地方发生,而不必在其他地方进行搜索。

用例 (Use Cases)

A couple examples goes a long way towards a complete understanding of services.

几个示例对于全面理解服务大有帮助。

  • console logs

    控制台日志
  • API requests

    API请求

Both are common across most applications. Having services to handle these operations will reduce component complexity.

两者在大多数应用程序中都很常见。 拥有处理这些操作的服务将降低组件的复杂性。

控制台日志 (Console Logs)

This example builds up from the base @Injectable skeleton. The skeleton is available through executing the CLI (ng generate service [name-of-service]]).

此示例从基础@Injectable骨架构建。 可通过执行CLI使用该框架( ng generate service [name-of-service]] )。

// services/logger.service.ts

import { Injectable } from '@angular/core';

interface LogMessage {
  message:string;
  timestamp:Date;
}

@Injectable({
  providedIn: 'root'
})
export class LoggerService {
  callStack:LogMessage[] = [];

  constructor() { }

  addLog(message:string):void {
      // prepend new log to bottom of stack
      this.callStack = [{ message, timestamp: new Date() }].concat(this.callStack);
  }

  clear():void {
      // clear stack
      this.callStack = [];
  }

  printHead():void {
      // print bottom of stack
      console.log(this.callStack[0] || null);
  }

  printLog():void {
      // print bottom to top of stack on screen
      this.callStack.reverse().forEach((logMessage) => console.log(logMessage));
  }

  getLog():LogMessage[] {
      // return the entire log as an array
      return this.callStack.reverse();
  }
}

LoggerService registers with the root module through the @Injectable metadata. Thus it can instantiate in the app.component.html.

LoggerService通过@Injectable元数据向根模块注册。 因此,它可以在app.component.html实例化。

// app.component.ts

import { Component, OnInit } from '@angular/core';
import { LoggerService } from './services/logger.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
  logs:object[] = [];

  constructor(private logger:LoggerService) { }

  updateLog():void {
      this.logger.printHead();
      this.logs = this.logger.getLog();
  }

  logMessage(event:any, message:string):void {
      event.preventDefault();

      this.logger.addLog(`Message: ${message}`);
      this.updateLog();
  }

  clearLog():void {
      this.logger.clear();
      this.logs = [];
  }

  ngOnInit():void {
      this.logger.addLog(“View Initialized”);
      this.updateLog();
  }
}

The template HTML provides further insight into the component’s use of LoggerService.

模板HTML可以进一步了解组件对LoggerService的使用。

<!-- app.component.html -->

<h1>Log Example</h1>

<form (submit)="logMessage($event, userInput.value)">
  <input #userInput placeholder="Type a message...">
  <button type="submit">SUBMIT</button>
</form>

<h3>Complete Log</h3>
<button type="button" (click)="clearLog()">CLEAR</button>
<ul>
  <li *ngFor="let log of logs; let i=index">{{ logs.length - i }} > {{ log.message }} @ {{ log.timestamp }}</li>
</ul>

This has the feel of a ToDo application. You can log messages and clear the log of messages. Imagine if all the logic from the service was shoved into AppComponent! It would have complicated the code. LoggerService keeps the log-related code encapsulated from the core AppComponent class.

这具有ToDo应用程序的感觉。 您可以记录消息并清除消息日志。 想象一下,如果服务中的所有逻辑都被推到了AppComponent中! 它将使代码复杂化。 LoggerService保留从核心AppComponent类封装的与日志相关的代码。

提取请求 (Fetch Requests)

Here is one more example worth playing around with. This example is possible thanks to typicode’s JSONPlaceholder1. The API is public and free to use.

这是另一个值得一试的例子。 由于typicode的JSONPlaceholder 1因此该示例成为可能。 该API是公开的,可以免费使用。

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

// https://jsonplaceholder.typicode.com
// public API created by typicode @ https://github.com/typicode

interface Post {
  userId:number;
  id:number;
  title:string;
  body:string;
}

@Injectable({
  providedIn: 'root'
})
export class PlaceholderService {
  constructor(private http:HttpClient) { }

  getPosts():Observable<Post[]> {
      return this.http.get('https://jsonplaceholder.typicode.com/posts');
  }

  getPost(id:number):Observable<Post> {
      return this.http.get(`https://jsonplaceholder.typicode.com/posts/${id}`);
  }
}

This is more of a stand-alone piece than a fully fleshed out example. Fetch requests tend to work better as an injectable service. The alternative is an over-complicated component. The injected class subscribes to what the PlaceholderService pre-configures.

与完全充实的示例相比,这更像是一个独立的片段。 提取请求倾向于作为可注入服务更好地工作。 替代方案是过于复杂的组件。 注入的类订阅PlaceholderService的预配置。

结论 (Conclusion)

Services and dependency injection are very useful together. They allow developers to encapsulate common logic and inject across multiple different components. This alone is a massive convenience for any future maintenance.

服务和依赖注入一起非常有用。 它们使开发人员可以封装通用逻辑并跨多个不同组件进行注入。 仅此一项就为将来的维护提供了极大的便利。

Injectors work as intermediaries. They mediate between instantiating components and a reservoir of registered services. Injectors offer these instantiable services to their branch children.

注入器充当中介。 它们在实例化组件和已注册服务的存储之间进行调解。 注入器为分支孩子提供这些实例化服务。

See the next few links for more information on services and dependency injection.

有关服务和依赖项注入的更多信息,请参见接下来的几个链接。

Angular资源 (Resources for Angular)

翻译自: https://www.freecodecamp.org/news/angular-services-and-dependency-injection-explained/

框架依赖注入和普通依赖注入

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值