---
# System prepended metadata

title: Day23 【牙起來】 元件執行順序 & 生命週期 - Angular

---

# Day23 【牙起來】 元件執行順序 & 生命週期 - Angular

再繼續往RxJS的道路之前，
先插播一則文章，回過頭來看Angular元件、服務、生命週期與執行的順序


## constructor、ngOnInit

透過`ng cli`產出的元件，底下都會有以下兩個方法(Method)

* `constructor()` Typescript的構建物件函式
* `ngOnInit()` Angular元件初始化時執行


在初學階段，這兩者都可以視作**元件初始化時**做的事情
只要知道`ngOnInit`執行的時機點晚於`constructor`一些

因為`constructor()` Typescript層的東西
其中小括號內`()`是構建函式的**Input參數**(Parameter)
把這個物件所需要用到、所依賴的**服務**注入進來，提供給這整個物件使用（讓物件內的每個方法都可以取用到）

昨天看到的 `HttpClient` 是Angular內建的眾多服務(Service)之一，就是透過**注入服務**到元件中讓元件能使用該服務底下的方法。未來我們也會自行寫服務`service.ts`，注入到自己寫的元件中。


所以執行順序為，
先執行構建物件，等構建完畢之後才執行Angular元件初始化

```typescript=
  constructor() {
    console.log('==== constructor ====')
  }

  ngOnInit(): void {
    console.log('==== ngOnInit ====')
  }
```

![](https://i.imgur.com/Ss3bV8g.png)

## 生命週期、執行順序

除了以上兩種預設的方法之外，還有很多**內建方法**

```typescript=

export class AppComponent implements OnInit, OnDestroy, AfterViewInit {

  constructor() {
    console.log('==== constructor ====')
  }

  ngOnInit(): void {
    console.log('==== ngOnInit ====')
  }

  ngAfterViewInit(): void {
    console.log('==== ngAfterViewInit ====')
  }

  ngOnDestroy() {
    console.log('==== ngOnDestroy ====')
  }
}

```

> 這一行 `implements OnInit, OnDestroy, AfterViewInit` 實作介面
> 有加、沒加都不會對畫面產生影響
> 
> 因為`Javascript`沒有`interface`，最終編譯都是相同結果
> 只是加了對程式碼風格較好，有助於IDE推斷介面型別
> 
> ![](https://i.imgur.com/s9i5fYr.gif)



執行結果

![](https://i.imgur.com/XjBskKa.png)

* `constructor` 構建一個物件首先執行的函式，在這裡引入物件所需用到的服務
* `ngOnInit` 生命週期 元件初始化，進入此元件做的事情，此時畫面尚未生成完畢
* `ngAfterViewInit` 生命週期 當畫面(View)渲染完畢才做的事
    > 例如抓取頁面上的某個節點，若在畫面出現之前執行的話會抓不到元素而變成`undefined`
* `ngOnDestroy` 生命週期 離開、結束此元件時做的事情
    > 刷新頁面或離開頁面**都不會觸發效果**
    > 因為是這兩件事情主導權不在Angular手上，而是由瀏覽器銷毀
    > 在未來提及`Rouing`切換頁面元件時可以看到效果


以人類的生命週期來對應的話，分別是
* 受精階段: `constructor` 建構胚胎卵，注入所需要的養分服務，以幫助未來成長
* 胎兒階段: `ngOnInit` 元件在媽媽的肚子裡面長好了
* 嬰兒階段: `ngAfterViewInit` 畫面生出來了，我們肉眼看的見四肢了
* 死亡階段: `destroy` 生命離開肉體軀殼，被大自然回收了


## 巢狀結構的執行順序

我們在 `app` 與 `store` 兩個元件中，都分別印出以上四種狀態

修改 `store.component.ts` 

```typescript=
...

export class StoreComponent implements OnInit, AfterViewInit, OnDestroy {

  constructor() {
    console.log('==== StoreComponent constructor ====')
  }

  ngOnInit(): void {
    console.log('==== StoreComponent ngOnInit ====')
  }

  ngAfterViewInit(): void {
    console.log('==== StoreComponent ngAfterViewInit ====')
  }

  ngOnDestroy(): void {
    console.log('==== StoreComponent ngOnDestroy ====')
  }
}
```

修改 `app.component.ts` 

```typescript=
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
  title = 'project03';

  constructor() {
    console.log('==== AppComponent constructor ====')
  }

  ngOnInit(): void {
    console.log('==== AppComponent ngOnInit ====')
  }

  ngAfterViewInit(): void {
    console.log('==== AppComponent ngAfterViewInit ====')
  }

  ngOnDestroy(): void {
    console.log('==== AppComponent ngOnDestroy ====')
  }

}
```

修改 `app.component.html`
```html=
<app-store></app-store>
```



結果畫面

![](https://i.imgur.com/TqEhQ3m.png)

可以看到巢狀的執行順序
先是**App**的建構，建構完畢跑進**Store**開始建構，接著開始Angular的生命週期，
從**APP**開始初始化，等**Store**初始化好了、畫面都好了，最終**APP**的畫面才好。


## 加上服務的執行順序


透過`ng cli`建立一個名為`svc`的服務

    > ng g s svc

修改`svc.service.ts`
```typescript=
import { Injectable, OnInit } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class SvcService implements OnInit{

  constructor() {
    console.log('SvcService constructor')
  }
  
}
```


接著分別在`app.component.ts` 與`store.component.ts` 中
加上這一段試試看效果

```typescript=
  constructor(svc: SvcService) {
  }
```

* 僅將`svc: SvcService`加在 `app.component.ts` 的結果
![](https://i.imgur.com/gFY4jNs.png)


* 僅將`svc: SvcService`加在 `store.component.ts` 的結果
![](https://i.imgur.com/q0OyTDZ.png)

由此可見，注入的服務是在`Construct()`的前一刻先被執行

---

## 服務(Service)沒有元件生命週期

服務(Service)沒有**Angular生命週期**
就算加了`ngOnInit`等方法，也不會有任何作用

**Angular生命週期**只有元件(Component)、指示(Directive)有


```typescript=
import { Injectable, OnInit } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class SvcService implements OnInit{

  constructor() {
    console.log('SvcService constructor')
  }

  ngOnInit() {
    console.log('SvcService ngOnInit')
  }
}
```




