iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 26
0
Modern Web

從巨人的 Tip 看 Angular系列 第 26

[Day 26] 從 AsyncPipe 出發,微探討 Angular 處理 pipe 的流程

  • 分享至 

  • xImage
  •  

昨天介紹了 AsyncPipe 的用法以及它可以帶來的便利,今天要來看一下在這方便的背後是由那些東西所組成的。

一切都從編譯之後開始

function AppComponent_ng_container_2_Template(rf, ctx) {
  if (rf & 1) {
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementContainerStart"](0);
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementStart"](1, "p");
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵtext"](2);
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵpipe"](3, "async");
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementEnd"]();
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementStart"](4, "p");
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵtext"](5);
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementEnd"]();
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementContainerEnd"]();
  }
  if (rf & 2) {
    const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_0__[
      "ɵɵnextContext"
    ]();
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵadvance"](2);
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵtextInterpolate1"](
      "This is subscribed by AsyncPipe: ",
      _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵpipeBind1"](
        3,
        2,
        ctx_r0.interval1
      ),
      ""
    );
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵadvance"](3);
    _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵtextInterpolate1"](
      "This is subscribed manually: ",
      ctx_r0.interval2Value,
      ""
    );
  }
}

↑ Block 1

rf & 1 為 true 的階段,Angular 會依序透過不同的 instruction 建立 element,在其中我們可以看到先前沒有看過的 instruction:ɵɵpipe

rf 是 RenderFlags 的縮寫。當 rf 被設為 0x01 的時候,代表進入 create block、設為 0x10 時,則進入 update block。相關說明可以參考:Link

當執行到 ɵɵpipe 這個 instruction 的時候,Angular 會建立指定 pipe 的實體,然後存入當前的 lView 與 tView.data。

最後則會進到 update block,進到這個階段的時候會有一個 ɵɵadvance 的 instruction,在開始處理 data binding 之前,Angular 會先用這個 instruction 將 element 的定位點移到實際有需要做 data binding 的那個元素的 index。

舉例來說,在 _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵtext"](2); 這個 index 為 2 的 text 元素有一個 interpolation,所以在進到 update block 時,Angular 就用 ɵɵadvance 把定位點移到 2,接著執行 ɵɵtextInterpolate1 把值填進去。

關於 ɵɵadvance,可以移到這裡,了解更多!

做完 interpolation 之後,接著就是做 ɵɵpipeBind1 了。

export function ɵɵpipeBind1(index: number, slotOffset: number, v1: any): any {
  const lView = getLView();
  const pipeInstance = load<PipeTransform>(lView, index);
  return unwrapValue(
      lView,
      isPure(lView, index) ?
          pureFunction1Internal(
              lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, pipeInstance) :
          pipeInstance.transform(v1));
}

↑ Block 2:ɵɵpipeBind1 的實作

ɵɵpipeBind1 這個 instruction 會根據 pipe 實體來選擇要怎麼呼叫 pipe 的 transform 方法,再透過 unwrapValue 來做一些額外的處理,最後將被 pipe 處理過的值傳出去給 ɵɵtextInterpolate1 instruction 來更新 text 元素的值。


以上是 Angular 處理 pipe 的流程,因為 AsyncPipe 是一個 impure 的 pipe,所以會直接呼叫 AsyncPipe 的 transform 方法,關於 pure 與 impure 之間的差異,就是明天的內容囉!

最後一週啦 ?

以下按照入團順序列出我們團隊夥伴的系列文章!

請自由參閱 ?


上一篇
[Day 25] pipe!在 HTML Template 上使用 async 處理 Observable
下一篇
[Day 27] 微探討 Pure pipe 與 Impure pipe
系列文
從巨人的 Tip 看 Angular30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言