[Day 26] 从 AsyncPipe 出发,微探讨 Angular 处理 pipe 的流程

昨天介绍了 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 26 | Overfitting v.s. Underfitting

>>:  【Day28】Pixi-Ticker

04
杂谈    

再谈中断与异常

想知道我们在使用滑鼠操作电脑时作业系统在背後做了什麽事情吗? 又或者为什麽我们在写 C 语言时,老师...

大盘到底能不能攻上一万八??

星期四(12/14)大盘跌幅近一个百分点,市场又是一片哀嚎 散户很容易犯的错就是 大涨不找理由,大跌...

[Day 27] 建立注册的画面及功能(十一) - Gmail设定(二)

今天要分享的是G-mail寄信的另外一种方式, 虽然比较麻烦, 但是比较安全. 解除人机验证锁定 进...

用React刻自己的投资Dashboard Day6 - 建立图表区元件,串接API取得数据

tags: 2021铁人赛 React 上一篇使用静态的资料,将多张数据资料表画成线图呈现在网页上,...

[专案上线第01天] - 新来的主管说要写 Vue Test Utils 单元测试

前言 该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系...