昨天介紹了 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 之間的差異,就是明天的內容囉!
以下按照入團順序列出我們團隊夥伴的系列文章!
請自由參閱 ?