RSS

קטגוריה: Angular 2.0

Config file for Angular CLI with AOT

Angular CLI supports const environment but you need to
compile the project for each environment.  But the IT guys dont want to run again and again the CLI for each environment.

The recipe:

1.

const config = {
    url :
'http://www.ynet.co.il'
}

 

2.  Add the file to index.html, like this.

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Webconfig</title>
    <base href="/">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/x-icon" href="favicon.ico">
    <script src="assets/config.js"></script>
</head>
<body>
<app-root></app-root>
</body>
</html>
 
3.  Now you can use the config variable everywhere. 
Example:

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
declare let config:{url:string};
if (environment.production) {
  enableProdMode();
}
console.log(`config url : ${config.url}`);
platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .catch(err => console.log(err));

Impotent: Don’t import the config.js like this: import {config} from './assets/config.js'; Because it will insert the file to the bundles files that CLI creates.
 
What you think?
 
2 תגובות

פורסם ע"י ב- אוקטובר 22, 2017 ב- Angular 2.0, angulr/cli

 

ERROR in Error encountered resolving symbol values statically

הצוות של אנגולר החליט שכדי לשפר את מהירות הקימפול של אנגולר בתהליך ה-AOT, הם לא יכולים להריץ קוד דינאמי בתוך ה-Decorators כמו למשל NgModule.

כלומר אם אתם רוצים לטעון לתוך ה-  RouterModule.forRoot רשמיה דינאמית של Routes אתם לא יכולים.

מעכשיו שרוצים לטעון Routes בצורה דינאמית צריך להשתמש בשרות Router במתודה config.

ראו התכתבות ב-GitHub:

error

 
השארת תגובה

פורסם ע"י ב- ספטמבר 11, 2017 ב- Angular 2.0

 

Performance Optimization in Angular 2.0

 

Angular 2 is very fast J. Its mechanisms: change detection, renderer, compiler and more have been redesigned and buildt from scratch. This brings the question why do we need performance optimization? Because we are addicted to speed! Over the years our applications have become larger and the UI has become more and more complex. In this post I will explain how change detection works (In Angular 1 it is called the digest loop) and how we can optimize it to improve performance.

 

How Angular 2 knows when to update the UI?

Angular 2 works with zone.js library. This library overrides all the functions that we register to async events (i.e setTimeout, setInterval, addEventListener and XMlHttpRequet).

The reason that Angular 2 uses the zone.js is to know when our handler finishes and then the NgZone service (NgZone is a class that wrap the zone service) calls to ApplicationRef.tick() method. The tick() method scans the tree components from top to bottom and calculates in each component the expressions that exist in the template. If the result of the expression is not equal to the previous result, (from the previous tick) Angular will update the DOM property that connects to this expression.

 

 What are the parameters that influence my performance?

Now that we know how Angular 2 works we can build the performance formula.

image

Frequency    – The number of times a tick method is call per second.

Quantity       – The number of expressions that exist in the tree components.

 

What are High Frequency Problems?

Usually the UI changes because we react with the UI events and these events don’t happen in high frequency (All the round brackets in the templates).

High frequency performance problems can often occur when the data needs to be updated in high frequency using timers or communication for example components like monitors, graphs, clocks. When these components cause a tick, the entire tree is recalculated regardless of whether or not the components in the tree need to be updated at such a high frequency.

Below is an example of high frequency performance problem.

image

In the dashboard we have one component that cause a tick every 50ms. This means if we working without any optimizations, all of the components in the tree are calculated every 50ms and this is bad for performance.

To improve the performance we need to reduce the number of ticks per second but still update the specific graph component at 50ms. We need to work with NgZone service and cancel the default behavior of executing the tick function after async events. See code:

image

I use the runOutsideAngular method to execute the run method so any async events that happen inside this method will not cause any tick. The value property will update every 50ms but we will not see the screen updates. We need to call explicitly to detectChanges() method. See code:

image

 

Summary of the High Frequency Problem:

When a component causes too many ticks and the other components don’t need this kind of high frequency refresh rate, we will use the NgZone service to eliminate the tick and the ChangeDetectorRef service to update only the component area in the screen.

 

What is the High Expressions Problem?

In every tick, Angular 2 calculates all the expressions that exist in the components tree. Less expressions means less calculations so the tick method will take less time and this means more time for the UI thread to do other tasks. The question is do we need to calculate each expression in every tick? Answer: of course not.

 

Detach & Reattach Strategy:
A component can detach form the tree components, meaning Angular will not calculate the component expressions on a tick and will not update the component area on the screen. Only when the component reattaches back to the components tree, Angular will calculate it expressions. A detach and reattach methods exist in the ChangeDetectorRef class. Each component can choose when to call this methods.

Notes:

1)    In detach mode the component can still cause a tick.

 

2)    When executing the reattach method, we see the first update only when a tick happens. We can call explicitly to detectChanges method to update the screen.

 

On-push Strategy:

If the state of a component changes because the component inputs are changed, then on-push strategy is recommended. To use the on-push strategy is very easy, see code:

@Component({
    selector :
'user'
,
    template :
`

`,
    changeDetection : ChangeDetectionStrategy.OnPush
})

export class
UserComponent{
    @Input() name:
string
;
    @Input() email:
string
;
    @Input() age:
number
;
}

 

Notes:

1)    We will see the component update on the screen only if one of the inputs is changed (name, email or age).

 

2)    Angular 2 compares expressions that return objects by reference. This means if a property in the object has changed and not the object reference, Angular will not update the component area on the screen. To solve this problem we need to use the ngDoCheck hook and the KeyValueDiffers class (See the NgClass directive code). In case of array we need to use the IterableDiffers class (See the NgFor directive code).

 

Threshold Strategy:

The goal of the threshold strategy is to update the component only if the state has changed significantly.

Example:

This demo shows how we can work with an Observable class and its operators to reduce the amount of updates, meaning less expressions to calculate. The component is detached form the component tree and the update happens only when item comes up from the observable. See code:

Threshold

let threshold = source

          .auditTime(500)

          .scan((acc,curr)=>{

                return {

                    curr,

                    delta: Math.abs(acc.curr – curr)

                }

           })

          .filter(value => value.delta > 15)

          .map(acc => acc.curr)

Up & Down triangle

threshold

        .scan((acc,curr)=>{

             return {

                        curr,

                        isUp: curr – acc.curr > 0

             }

        })

        .map(val => val.isUp)

        .distinctUntilChanged();

 

Link to live demo.

 

Summary:

Angular 2 is Fast, but not enough to overcome huge components tree with high frequency of ticks. In this cases we must optimize and use the NgZone to reduce the number of ticks and the ChangeDetectorRef class to reduce the number of expressions for each tick.

image

These optimizations reduce the number of calculations the UI Thread does per second, meaning more efficiency.

 
השארת תגובה

פורסם ע"י ב- דצמבר 20, 2016 ב- Angular 2.0

 

Injecting Components in Runtime

This post explains how to create component in runtime. I will show two scenario:

1.      How to inject a component in runtime without knowing which component will inject until runtime.

2.      How to inject HTML with components in runtime. The HTML will creates in runtime by some logics.

The code is based on Angular 2 RC 6.

Click here for live example.


Demo 1 – Inject component in runtime

The goal:

Injecting components in runtime that have not been loaded or compiled before on the client side.

clip_image002

When we click on the button “Dynamic component (Start)” the application starts add string to the shapes array every second. The string is random form names of shapes (circle, triangle, square and rectangle). Each string converts to component. Only when we click on button the components load and compiles.

Code explanations:

Only the shape-dynamic-loader component (shape.component.ts) needs to be explained, all the others are pretty obvious.

1.      The template of this component is very simple; Placeholder for the shape’s component (circle, square, triangle and rectangle).

        <span #span>span>

 

2.      I use @ViewChild to get a ViewContainerRef of the span element. I will use it for creating the right shape component.

        @ViewChild('span', { read: ViewContainerRef }) span;

 

3.      Every time I set the source input, the createComponent method is executed.

_shape:string;
@Input(
'source'
)
set
shape(value){
this
._shape = value;
this
.createComponent();
}

 

4.      The createComponent method does all the hard work.

createComponent(){
let
injector = ReflectiveInjector
.fromResolvedProviders([],
this
.vcRef.parentInjector);
// 1. Create module loader
let loader = new SystemJsNgModuleLoader(this
.compiler);
loader.load(
'app/shapes/shapes.module'
)
.then((nmf:NgModuleFactory<
any
>)=>{
// 2. create NgModuleRef
let
ngmRef = nmf.create(injector);
let shape = ngmRef.instance.shapes.get(this
._shape);
// 3. Create component factory
let
cmpFactory = ngmRef
.componentFactoryResolver
.resolveComponentFactory( shape );
// 4. Create the component
let componentRef = this.span.createComponent(cmpFactory,0
,injector,[]);
// 5. Init the component name field.

            componentRef.instance.name = this._shape;
// 6. Refresh the component area.

            componentRef.changeDetectorRef.detectChanges();
componentRef.onDestroy(()=> {
componentRef.changeDetectorRef.detach();
});
});
}

 

Demo 2 – Inject HTML with components in runtime

The goal:

Injecting in runtime HTML with components that have not been loaded or compiled before on the client side.

clip_image004

When we click on Dynamic HTML button the application will create HTML string and compile it and add it to the DOM.

Code explanations:

This demo is more complicated because we need to create a HTML on the fly. We need to load the components that exist in the HTML string that we created in runtime.

1.      Create module loader same as the first demo. createDynamicComponentFromHtml method.

2.      Load the modules that have the components that we need, for the HTML. Again, same as first demo.

3.      Create component in runtime that has the HTML.


Capture

As you can see, this is a simple template. Usually we create here dynamic template base on    some logics.

4.      Create a module that imports all the modules I need for the template. After the module is created, I have to compile it.

createDynamicFactory(injector,moduleClass){
@Component({
selector :
'dynamic-html'
,
template :
`…`
})
class
DynamicHtmlComponent{}
@NgModule({
imports        : [moduleClass],
declarations   : [DynamicHtmlComponent],
entryComponents: [DynamicHtmlComponent]
})
class
DynamicModule{}
return this
.compiler
.compileModuleAsync(DynamicModule)
.then((ngMdlFactory)=>{
let
ngMdlRef = ngMdlFactory.create(injector);
// Create component factory
let
cmpFactory = ngMdlRef.componentFactoryResolver
.resolveComponentFactory( DynamicHtmlComponent );

return cmpFactory;
});
}

This method does 3 imported steps:

a.      Compile the module and return NgModuleFactory.

b.      Create NgModuleRef from NgModuleFactory.

c.      Create ComponentFactory from NgModuleRef.

5.      Now that I have ComponentFactory the rest of the code is same as first demo.

this.createDynamicFactory(injector,ngMdlRef.instance.constructor)
.then((cmpF)=>{
// Create the component
let componentRef =  this.span.createComponent(cmpF,0
,injector,[]);
componentRef.changeDetectorRef.detectChanges();
componentRef.onDestroy(()=> {
componentRef.changeDetectorRef.detach();
});
});

 

 

Summary

First demo shows you how we can create a component in runtime. This scenario is good when you don’t know in advance which component you need to use. In our example the list is not homogeneous, I don’t know the shapes until runtime. After the module loaded to the client it will not load again.

Second demo shows you how to create HTML in runtime with components; compile it and inject it.

The demos shows you in action the classes:

1.      SystemJsNgModuleLoader

2.      Compiler

3.      NgModuleFactory

4.      NgModuleRef

5.      ComponentFactory

6.      ViewContainerRef

7.      ChangeDetectorRef

I hope this information is helpful for you; send feedback please :=).

The next course opens on 18 September. For more information click here.

 
4 תגובות

פורסם ע"י ב- ספטמבר 4, 2016 ב- Angular 2.0

 

NgModule Decorator Deep Dive

 

In this post I want to emphasize some facts that help you understand the “ANGULAR MODULES (NGMODULE)” article.

1.          The services classes have different behaviors from Components, Directives and Pipes (CDP) in Angular Injector.

a.     Service behaviors in injector:

                                        1.     Singleton Instance – When you register a service to the Injector, you get a singleton instance.

                                        2.     Bubble – When a component wants to inject a service, Angular first looks at the component injector (child) and if the service doesn’t exist, it searches in the parent component injector (“bubble”). The Injector continues to go up until it finds the service. The root parent Injector belongs to platform object.

 

b.      CDP behaviors in injector:

                                        1.     Not singleton – When you use a directive or component in a template, you get a new instance of the directive/component. For example, if you use same directive number of times in a template, you get many instances of the directive.
 

                                        2.     Not bubble – You can’t register a directive in a parent component and use it in a child component.

 

2.          If a module loads normally, it doesn’t create an injector. If a module loads in a lazy way, it creates an injector for the module scope.

3.          Split the properties of NgModel Decorator to two groups: one for services and one for CDP.

a.     Group I – Properties for services classes:

                                        1.     Providers

b.     Group II – Properties for CDP classes:

                                        1.     Declarations

                                        2.     Imports

                                        3.     Exports

                                        4.     Bootstrap

 

Now we can start to explain the NgModule properties:

 

Group I – Properties for services classes:

§  @NgModule.providers – all the classes listed here are registered to the application injector as singleton (not in each component or directive metadata @component.providers that declares in @NgModule.declarations property). Anybody can ask for this singleton instance.
We have one exception; the lazy module has it on Injector. Meaning, the services listed in module providers are registered in the module injector instead of the application injector. It makes this service only available
to this module.

 

Group II – Properties for CDP classes:

§  @NgModule.declarations – all the CDP listed here know each other. It is the same as to register each component (@Component.directives) to all the other’s components. This property affects only the classes (CDP) defined in this property.

Example: declarations = [Compoent1, Component2, Component3, Directive1, Directive2, Pipe1, Pipe2 ]


clip_image002

 

Note: Each component knows all the others. Directive and pipe don’t have a template so they don’t need to know anybody.

 

§  @NgModule.exports – List of components, directives and pipes (CDP) that will be visible to modules that import this module.

 

§  @NgModule.imports – Everything from the imported modules that declares as an export, in the imported modules, will be available to declarations of this module.

 

Example:

1.     ModuleA ( declarations=[ Component1], imports:[ModuleB] )

2.     ModuleB ( declarations=[ Component2, Component3], exports:[ Component3] )

clip_image004

                        Component1 can use Component3 in a template but can’t use Component2.

 

§  @NgModule.bootstrap – Array of components to bootstrap. Angular loads this array to the DOM during the bootstrap (application launch) process. Use it only in root module (main).

Summary
This post is not instead of reading the ANGULAR MODULES (NGMODULE)” article, it just to emphasize some points in the article to make it more readable. I hope this information is helpful for you; send feedback please :=).

The next course opens on 18 September. For more information click here.

 

 
השארת תגובה

פורסם ע"י ב- אוגוסט 30, 2016 ב- Angular 2.0, AngularJS Tips

 

Custom Group Validation in Angular 2

 

Angular 2 has improved the way we write custom validation. There are a lot of articles of how to do it. In this post I want to focus on how to build custom group validation in model driven development. I will build a custom group validation (CGV) that checks each item in the formArray that has a unique value.

The code for the model:

namesArray = new FormArray([], this.customGroupValidation );
myForm =
new
FormGroup({
    inputName:
new FormControl("
),
    names    :
this
.namesArray
});

 

I use the FormArray class instead of FormGroup in the names field because the number of names is unknown; it is dynamic. The user can add multiple names.

 

The template code:

 

<form [formGroup]="myForm">
    name : <
input type="text" formControlName="inputName"
>
    <
button (click)="add()">Add</button><br
>
    <
hr
>
    <
div class="left"
>
        names: <
br
>
        <
ul formArrayName="names"
>
            <
li *ngFor="let item of namesArray.controls; let i = index"
>
                <
input type="text" [formControlName]="i"
>
                <
button (click)="removeAt(i)">X</button><br
>
            </
li
>
        </
ul
>
        <
div *ngIf="namesArray.hasError('duplicate')"
>
            duplicate entries
        </
div
>
    </
div
>
</
form
>

 

clip_image002

The code for add and remove names:

add(){
   
this
.namesArray.push(
       
new FormControl(this.myForm.get('inputName'
).value)
    );
}
removeAt(i:
number
){
   
this
.namesArray.removeAt(i);
}

 

Now let’s see the custom group validation method. I used groupBy method of lodash library to detect if there are any groups of more than one item, which means that we have duplicate names.

customGroupValidation (formArray) {
   
let isError = false
;
   
var
result = _.groupBy( formArray.controls , c => c.value );
   
for (let prop in
result) {
       
if (result[prop].length > 1
) {

            isError = true;
            _.forEach(result[prop],
function
(item:FormControl) {
                item._status =
"INVALID";

           
});
        }
else
{
            result[prop][
0]._status = 'VALID';           

       
}
    }
   
if(isError){ return {'duplicate':'duplicate entries'
}}
}

 

The result of the custom group validation is that every time we add or change name to a value that already exists in the formArray, the two formControl with the same value will be invalid. In addition the parent formArray will also be invalid.

clip_image004

If I delete or change one of the duplicates names, the form will go back to be valid (in this case ‘Eyal’ name).

I hope this information was helpful for you. Try the live example.

This is one of many examples that I show in my AngularJS 2 course (.html"ng-course).

The next course opens on 18 September. For more information click .html"heHYPERLINK "http://ng-course.org/ng-course/courses/angular2.html"rHYPERLINK "http://ng-course.org/ng-course/courses/angular2.html"e.

 
תגובה אחת

פורסם ע"י ב- אוגוסט 28, 2016 ב- Angular 2.0, AngularJS Tips

 

Tips and Tricks 1 – Angular 2 Routing

When you use RouterModule.forRoot method to register the routes for the router object, the method has a second parameter of type ExtraOptions interface.

export interface ExtraOptions {
enableTracing?:
boolean
;
useHash?:
boolean
;
}

 

enableTracing = true :

Print to the console the navigation events: NavigationStart, RoutesRecognized and NavigationEnd. It can be very helpful information.

 

useHash = true:

Change the location strategy from path to hash. This is a short version of:

{ provide:LocationStrategy, useClass: HashLocationStrategy }. In the development environment I prefer to work with hash because it doesn’t break in F5 (reload).

The next Angular 2 course (ng-course.org) is going to be on 18, 21, 25, & 28 in September.

 
השארת תגובה

פורסם ע"י ב- אוגוסט 21, 2016 ב- Angular 2.0, AngularJS Tips

 

Angular2 in memory web api

Angular2 in memory web api

 

באנגולר 2 אפשר להשתמש בספריה ‘angular2-in-memory-web-api’ כדי לבטל את התקשורת הפיזית לשרת ולעבוד מול מידע שנמצא בזיכרון, טוב לבדיקות.

שלב ראשון מחלקה שתחזיק את המידע בזיכרון. ראו קוד:

export class InMemoryDataService {
createDb() {
return { users:[
// users resource
{…},
// user object
{…},
// user object
…   
// users objects
]};
}
}

 

הדגשים:

1.     אנגולר יקרה למתודה createdDb בפעם הראשונה שתנסו לפעיל את המחלקה Http.

2.     ה- users מחליפים את ה- resource ב- web-API שעליו ניתן לעשות פעולות CRUD ע"פ החוקים של REST. למשל ‘app/users/12’ תביא את המשתמש עם id שווה ל- 12.

 

שלב שני בניית מערך לשימוש ה- Injector הראשי.

 

export const HTTP_IN_MEMORY = [
    HTTP_PROVIDERS,
    { provide: XHRBackend, useClass: InMemoryBackendService },
    { provide: SEED_DATA , useClass: InMemoryDataService },
    { provide: InMemoryBackendConfig, useValue: { delay: 600 } }
];
 
דגשים:

1.     השרות XHRBackend הוא זה שמבצע בפועל את התקשורת לשרת, לכן 
צריך להחליף אותו עם השרות InMemoryBackendService שבמקום לבצע
תקשורת יקרא ל- SEED_DATA, שזה בעצם המחלקה שאנחנו כתבנו, 
שיוצרת את מבנה הנתונים בזיכרון.

2.     השרות InMemoryBackendConfig מאפשר לנו לתת הגדרות של התנהגות,
כמו למשל המתנה של 600 MS בין הקריאה לחזרת התשובה. 
ניתן לראות את כל האפשרויות בממשק הבא:

export interface InMemoryBackendConfigArgs {
    // default response options
    defaultResponseOptions?: ResponseOptions;
    // delay (in ms) to simulate latency
    delay?: number;
    // false (default) if ok when object-to-delete not found; else 404     
    delete404?: boolean;
    // host for this service
    host?: string;
    // root path before any API call
    rootPath?: string;
}
 
 
שלב אחרון: חיבור ל- bootstrap.
 
bootstrap(App,[ HTTP_IN_MEMORY ]);
 
סיכום:

 

השרות הזה יכול לעזור לכם בפיתוח ובבדיקות. אשמח לקבל פידבקים.

 

מאמר זה הוא חלק התוכן שאני מעביר בקורסים שלי.
הקורס הבא יהיה ב- 18 לספטמבר. לפרטים נוספים הירשמו כאן: ng-course.org
.

 

 
השארת תגובה

פורסם ע"י ב- יולי 4, 2016 ב- Angular 2.0, Uncategorized

 

Angular 2 The Clock Component

באנגולר 2 אחרי כל אירוע אסינכרוני יש tick שנקרה ע"י ה-zone. אם יש הרבה אירועים אסינכרוניים בשנייה אנחנו יכולים לגרום לבעיית ביצועים.

בפוסט זה אני רוצה להסביר איך לכתוב רכיב שעון בדיוק של 50 ms. בחרתי את הקוד הבסיסי  לשעון שלי:

setTime(){
let t = new
Date();
this.time =
`
${t.getHours()}

        :
${this.formatNum(t.getMinutes())}
        :
${this.formatNum(t.getSeconds())}
        :
${t.getMilliseconds()}`;
setTimeout(
this.setTime.bind(this),50
);
}
formatNum(i){
return i < 10 ? `0${i}`
: i; }

 

שימו לב:

אני משתמש ב- setTimeout ולא ב- setInterval כדי לא ליצור עומס על ה- queue במידה וה- UI Thread עמוס ואז הוא לא מצליח למשוך מהתור את הפונקציות בקצב שה- setInterval מיצר אותם.

 

שלב א: לעבוד מחוץ לאנגולר

אני לא רוצה שכל 50 ms יבוצע tick במערכת. (המשמעות של tick  היא שאנגולר עובר על עץ הרכיבים ובודק מה השתנה ואז מעדכן את ה- UI. ראו פוסטים בנושא. ) לכן אני אשתמש ברכיב ה- NgZone.

constructor(zone:NgZone) {}
ngOnInit(){
    this.zone.runOutsideAngular(()=> {
        this.setTime();
    });
}
 
הקוד הנ"ל מוציא את ה- setTimeout ממנגנון ה- zone. כלומר עכשיו ה- 50 ms לא גורמים ל- tick.
 

שלב ב: לעדכן את המסך

אני אשתמש ביכולות של ה- ChangeDetectorRef והפונקציה detectChanges, מחשבת את כל החלקים הדינאמים בתבנית (למשל {{}} או [] ). ראו קוד:

@Component({
    selector: 'clock',
    template: `<span>{{time}}</span>`
})
export class Clock extends BaseDemo{
    time:string = '00:00:00:000';
    isDestroy:boolean = false;
    constructor(zone:NgZone,
                cd:ChangeDetectorRef) {}
    ngOnInit(){
        this.cd.detach();
        this.zone.runOutsideAngular(()=> {
            this.setTime();
        });
    }
    setTime(){
        if(this.isDestroy) return;
        let t = new Date();
        this.time = `
            ${t.getHours()}
            :${this.formatNum(t.getMinutes())}
            :${this.formatNum(t.getSeconds())}
            :${t.getMilliseconds()}`;
        this.cd.detectChanges();
        setTimeout(this.setTime.bind(this),50);
    }
    formatNum(i){ return i < 10 ? `0${i}` : i; }
    ngOnDestroy(){
        this.isDestroy = true;
    }
}

 

סיכום:

יש הרבה רכיבים שיש להם תדירות גבוהה של עדכון מסך. שימוש ברכים אלו יגרמו ל- tick שיגרום לעדכן את כל האפלקציה. בפוסט זה אני מראה לכם איך לשלוט בתדר העידכון ע"י ניתוק מה- zone וקריאה ל- detectChanges כל פעם שרוצים לעדכן את הרכיב על המסך. עדכון זה לא גורם ל- tick.

כמו תמיד אשמח לפידבקים.

למידע נוסף בנושא, אשמח לראות אותכם בקורס אנגולר  2 שלי ng-course.

 
תגובה אחת

פורסם ע"י ב- יוני 25, 2016 ב- Angular 2.0, Uncategorized

 

Pure Pipe vs. Impure Pipe

 

בפוסט זה אני רוצה להסביר את ההבדלים בין שני סוגי ה- Pipe. בשביל להסביר את ההבדלים בניתי את שני ה-pipes הבאים, ראו קוד:

import {Pipe} from '@angular/core';
let counter:number = 0
;
export class MyPipe implements
PipeTransform {
    counter2:
number = 0
;
   
constructor
(){ counter++; }
    transform(value:
string,name:string
) {
       
return `n: ${name} v: ${value} c2: ${this.counter2++} c1:${counter}`
;
    }
}
@Pipe({ name:
'myPurePipe', pure: true
})
export class MyPurePipe extends
MyPipe{
   
constructor(){ super
(); }
}
@Pipe({ name:
'myImpurePipe', pure: false
})
export class MyImpurePipe extends
MyPipe{
   
constructor(){ super
(); }
}

 

נשתמש ב-Pipes באופן הבאה:

myPurePipe  : {{ 1  | myPurePipe  : 'a' }}

myPurePipe  : {{ 1  | myPurePipe  : 'a' }}
myImpurePipe: {{ 2  | myImpurePipe: 'b' }}

myImpurePipe: {{ 2  | myImpurePipe: 'b' }}

 

תוצאות:

 

Pipe

Type

Num of Instances

Num of Executes

myPurePipe

Pure

1

2

myImpurePipe

Impure

2

Many == Ticks

 

הסברים:

א.    Pipe מסוג pure לא נוצרים מספר מופעים, כלומר זה singleton. המתודה transform מופעלת כאשר יש tick רק עם ה- inputs שונים מה-tick הקודם. במקרה שלנו 1 ו- ‘a’ לא משתנים ולכן ה- myPurePipe  פועל רק פעם אחת  כפול מספר הפעמים שאני משתמש בו בתבנית, כלומר 2.

ב.     Pipe מסוג impure נוצר instance כמספר הפעמים שהוא מופיעה בתבנית. בנוסף הוא מופעל כל tick.

שאלה: באיזה סוג של pipe אני צריך להשתמש?

כאשר משתמשים ב-pure תחשבו על מתודה דטרמיניסטית, אם מקבלים את אותו הקלט נחזיר תמיד את אותו הפלט. מכאן נובע שאנחנו לא צריכים מספר מופעים.

Pipe שהוא impure הוא לא דטרמיניסטית ולכן צריך להפעיל אותו בכל tick. יש סבירות גבוהה שאנחנו נצטרך לשמור נתונים שונים לכל pipe שמופיע בתבנית ולכן אנחנו צריכים מספר מופעים כדי לשמור את הנתונים השונים. דוגמא:

@Pipe({ name: 'sumRandomPipe', pure : false })
export class SumRandomPipe implements
PipeTransform {
    sum:
number = 0
;
    transform(min:
number, max:number
) {
       
this.sum +=  Math.floor(Math.random() * (max – min + 1
)) + min;
       
return this
.sum;
    }
}

 

ביצועים:

כל אירוע אסיכרוני, timers ,UI ותקשורת גורמים ל-ticks מכאן נובע שב- impure צריך לבצע כל פעם מחדש את המתודה transform בלי קשר אם הקלט השתנה או לא, זה יכול לגרום לנו לבעיית ביצועים. בנוסף לא נשכח שלכל שימוש ב-pipe נוצר instance ושימוש מופרז יכול ליצור בעיות של זיכרון.

כמו תמיד כל תגובה מבורכת.

אשמח לראות אותכם בקורס שלי על AngularJS 2.

 

 

 
השארת תגובה

פורסם ע"י ב- יוני 15, 2016 ב- Angular 2.0