[Angular] Day18. Introduction to services and dependency injection

在开发专案时你一定会使用到 Service 的技巧,Service 是一个广泛的类别,包括 app 所需要的任何功能、数据或特性,而通常一个 service 是一个具有狭窄且明确定义目的的 class,简单来説可以想像成一个 service 只会对一个明确的目的提供所以有服务。

Angular 将 component 与 service 拆分开以增加模块化与可重用性,将处理 component view 的功能与其他类型的功能拆发开来可以让你在开发 component 时更精简高效,所以理想的情况下 component 中的逻辑只用来处理使用者的操作,component 应该提供 property binding 的 property 与 event binding 的 method 仅此而已。

而较为复杂的逻辑任务就应该委托给 service,比如从 server 中获取数据验证用户输入直接登陆到控制台等等复杂的逻辑处理都应该在 service 中处理掉,将这些复杂的逻辑写在 service 中就可以让他们被任何 component 使用。

不过说了这麽多,其实 Angular 是不强制你做这些动作的,不过建议再开发大型专案时还是将复杂的逻辑从 component 中移到 service 中,保持你的 component 单纯乾净也让 service 可以透过 inject 提供给其他 component 使用。

https://ithelp.ithome.com.tw/upload/images/20210813/20124767bKqlcXTE3g.png


What is dependency injection?

dependency injection 可以简单地称为 DI ,它是一种设计模式 当你要使用一个 class 时,可以直接从外部来源请求而不是像传统的做法将它实例化,它存在於整个 Angualr 中,他可以让你的程序保持灵活、可测试与弹性,component 可以在不知道如何创建 service class 的情况下使用到它的内容,简单来说 DI 让使用者可以不用去了解提供者的一些不重要的信息。


Service examples

介绍玩什麽事 DI 後,接着来做一个小小的例子,这是再开发专案时基本上都会遇到的

  1. 首先利用 Angular CLI 建立一个 service

    ng generate service project
    ng g s project
    
  2. 打开 project.service.ts

    import { Injectable } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class ProjectService {
    
      constructor() { }
    }
    

    首先看到的是这个档案使用了 @Injectable() 将这个 class 装饰成 Angualr 可以在 DI 系统中使用的,接着可以看到在他的 matedata 中定义了 provideIn: 'root' 这代表这个 service 在整个 app 都是可以被使用的,如果不指定 provideIn 的话在 component 中将无法直接注入到 component 中,举个例子

    import { Injectable } from '@angular/core';
    
    @Injectable()
    export class ProjectService {
    
      constructor() { }
    }
    

    上面的 service 没有在 metadata 中设定 providedIn,这个情况下如果跟平常一样在 component 中注入这个 service 就会出错

    import { Component, OnInit } from '@angular/core';
    import { ProductService } from '../../second/product.service';
    
    @Component({
      selector: 'app-third',
      templateUrl: './third.component.html',
    })
    export class ThirdComponent implements OnInit {
    
      constructor(private productService: ProductService) {}    // (1)
    
      ngOnInit(): void {
        console.log(this.productService.getName());             // (2)
      }
    
    }
    
    • (1): 在 component 的 constructor 中注入 service
    • (2): 在 component init 後调用 service 中的 method

    https://ithelp.ithome.com.tw/upload/images/20210813/20124767b8wiRUhh2R.png

    在 console 中就会看到这个错误,代表他找不到 ProductService 这个 provider 可以注入到 component 中,要解决这个问题需要在 component 的 metadata 中添加 providers 这个 property 并将要注入的 service 放进去这样就可以正常使用了

    import { Component, OnInit } from '@angular/core';
    import { ProductService } from '../../second/product.service';
    
    @Component({
      selector: 'app-third',
      templateUrl: './third.component.html',
      providers: [ProductService]
    })
    export class ThirdComponent implements OnInit {
    
      constructor(private productService: ProductService) { }
    
      ngOnInit(): void {
        console.log(this.productService.getName());
      }
    
    }
    
  3. 最後要将 service 注入到 component 中,虽然上面已经用了不过还是讲一下,要注入 service 到 component 中,要在 component 的 constructor 中将它注入,这要就可以在这个 component 中使用这个 service 提供的服务

    import { Component, OnInit } from '@angular/core';
    import { ProductService } from '../../second/product.service';
    
    @Component({
      selector: 'app-third',
      templateUrl: './third.component.html',
      providers: [ProductService]
    })
    export class ThirdComponent implements OnInit {
    
      constructor(private productService: ProductService) { }    // (1)
    
      ngOnInit(): void {
        console.log(this.productService.getName());
      }
    
    }
    
    • (1): 在 component 的 constructor 中注入 service

结论

本章中介绍了如何建立一个 service 并使用 dependency injection 将它注入到 component 中,虽然也介绍了什麽是 dependency injection,不过 DI 的观念比上面介绍的在复杂更多,比如说 @Injestable() 中的 metadata providedIn 就可以填入 rootmodule nameany 填入每个值都有对应不同的使用场景,其中的关系有点复杂就不在本篇章中介绍,一方面是我也不是非常了解不敢随便分享怕分享了错误的资讯,等之後我在摸熟一点会再开一个系列讲解这方面的资讯,所以这边就大概介绍基本的观念而已/images/emoticon/emoticon46.gif

下一篇将会介绍上面有提到的内容,当 @Injestable 没有设定 providedIn 时需要在 component 的 metadata 中添加 providers 这个其实是个缩写,详细内容就明天再仔细讲解吧,那就明天见!


Reference


<<:  【Day6】 Introduction

>>:  day18 : kafka服务应用 on K8S (下)

Day 19 「完美不完美」TDD 的困难之处

图片截自联合新闻网 笔者最近在看一个邀请影视明星来进行专业运动的节目:「全明星运动会」。节目是蛮有...

Day28 黯然消魂饭-自制蜜汁叉烧

经典的粤式烧腊的主角之一-叉烧,是许多人喜爱的烧腊之一 这次自制叉烧酱腌了2-3天的叉烧肉,搭配烤...

滤镜-30天学会HTML+CSS,制作精美网站

前一章节介绍过混合模式,相信对滤镜也不会很陌生。「滤镜」是什麽呢?他可以做出与Photoshop相同...

【Day 07】C 的输入输出函式

输入输出函式(printf、scanf)是 C 语言中非常重要、也很常用到的函式。如果要用到这两个函...

Day 24 [编程03] [译文] 如何在JavaScript 中更好地使用数组

文章选自 作者:sea_ljf 连接:https://juejin.im/post/68449036...