今天要介绍的 Tip 是有关於 pipe 的 pure 与 impure,当没有任何额外的设定下,自行建立的 pipe 都会是属於 pure pipe,这一点我们可以从原始码的说明得知:
export interface Pipe {
/**
* The pipe name to use in template bindings.
* Typically uses [lowerCamelCase](guide/glossary#case-types)
* because the name cannot contain hyphens.
*/
name: string;
/**
* When true, the pipe is pure, meaning that the
* `transform()` method is invoked only when its input arguments
* change. Pipes are pure by default.
*
* If the pipe has internal state (that is, the result
* depends on state other than its arguments), set `pure` to false.
* In this case, the pipe is invoked on each change-detection cycle,
* even if the arguments have not changed.
*/
pure?: boolean;
}
↑ Block 1:Pipe 的 interface
因为 pipe 密切的与 HTML template 合作,所以每一次的 change detect 都有可能会需要重新使用 pipe 来处理资料,并转成指定的格式输出。
而 pure pipe 的特性就是,它只有当传入的值是 string、number、boolean 等原生型别时,Angular 才会执行 pure pipe 的 transform 方法。如果传入的值是一个 Array 或是 Object,除非这两者的 reference 有被变更,否则并不会触发 pure pipe 的 transform 方法。
impure pipe 的特性与 pure pipe 刚好相反,每当有 change detection 发生时,Angular 就会执行 impure pipe 的 transform 方法。建立 impure pipe 的方法也非常简单,只需要将 Pipe decorator 的 pure 属性设为 false 就可以了。
两者间的差别可以用下方的简单范例来证明:
@Pipe({
name: 'filter',
pure: true
})
export class FilterPipe implements PipeTransform {
transform(value: Array<Obj>): Array<Obj> {
return value.filter((obj: Obj) => obj.show);
}
}
↑ Block 2:Pure pipe
@Pipe({
name: 'impureFilter',
pure: false
})
export class ImpureFilterPipe implements PipeTransform {
transform(value: Array<Obj>): Array<Obj> {
return value.filter((obj: Obj) => obj.show);
}
}
↑ Block 3:Impure pipe
<label>Name:</label><input #a>
<label>title:</label><input #b>
<label>show:</label><input #c>
<button (click)="append(a.value, b.value, c.value)">Append</button>
<div>
<p>Impure:</p>
<ng-container>
<p *ngFor="let item of (objs | impureFilter)">{{ item | json }}</p>
</ng-container>
<p>Pure:</p>
<ng-container>
<p *ngFor="let item of (objs | filter)">{{ item | json }}</p>
</ng-container>
</div>
↑ Block 4:HTML template
结果:
↑ Image 1
昨天的文章有稍微提到 ɵɵpipeBind1
这个 instruction,两种不同 pipe 的差异其实也就在这个 instruction 里:
isPure(lView, index) ?
pureFunction1Internal(
lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, pipeInstance):
pipeInstance.transform(v1));
↑ Block 5
impure pipe 的处理相对简单,因为对於 Angular 来说,这类型的 Pipe 在每次的 change detection 就是都去执行 transform 方法就好,完全不做其他比对的处理。
而 pure pipe 的行为就稍微复杂一些,Angular 会另外呼叫一个 pureFunction1Internal
函式:
export function pureFunction1Internal(
lView: LView, bindingRoot: number, slotOffset: number, pureFn: (v: any) => any, exp: any,
thisArg?: any): any {
const bindingIndex = bindingRoot + slotOffset;
return bindingUpdated(lView, bindingIndex, exp) ?
updateBinding(lView, bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
getPureFunctionReturnValue(lView, bindingIndex + 1);
}
↑ Block 6:pureFunction1Internal 函式
Block 6 的 pureFunction1Internal 函式内还呼叫了 bindingUpdate
来协助判断传入的值跟上一次保留的值有没有不同,有更新的话才会呼叫 pureFn,并使用 updateBinding 函式来更新 lView 内的资料,如果没有更新的话,就会直接透过 getPureFunctionReturnValue 这个函式来取得上次保留的值。
以上就是关於 pure pipe 与 impure pipe 的介绍!
虽然从原始码的角度来看,impure pipe 反而做了比较少的处理就直接呼叫 transform 方法,但实际对於效能而言,会因为 transform 方法的实作内容而有不同程度的影响,若在 impure pipe 的 transform 方法内塞了很多的逻辑运算,当传入的资料量越大,就会更显着的拖慢应用程序的效能。
以下按照入团顺序列出我们团队夥伴的系列文章!
请自由参阅 ?
<<: [DAY 28] 复刻 Rails - Routing 威力加强版 - 2
>>: Day 27 - 使用 CDK 创建 CloudWatch 也能发送 Alarm 到 LINE 的系统
!前提小补充! UI: User Interface(使用者介面),设计页面,须注意到网页页面使用的...
透过昨天的范例我们知道要绑定HTML属性需要使用v-bind指令,而今天我们要介绍的是v-bind绑...
空中传爱 ( 广播 ) 教学原文参考:空中传爱 ( 广播 ) 这篇文章会介绍如何使用「发送广播」、「...
Colab连结 资料增强(Data Augmentation),是一个当今天资料集样本不多时,透过调...
前言 你使用过Prototype,那你知道它可以被污染吗? 正文 概念 Javascript的物件透...