Превышаем скоросные лимиты с angular 2
TRANSCRIPT
Превышаем скоростные лимиты с Angular 2
Алексей Охрименко
IPONWEB
1
#rtb_techday
2
#rtb_techday
3
#rtb_techday
4
#rtb_techday
5
Алексей Охрименко
Twitter: @Ai_boy
6
7
IPONWEB
RTBDSPSSP
8
последствия превышения скорости (в реальной
жизни)
9
последствия превышения скорости*
* - поищите в Google Image - 4-ый результат
10
Всегда успеете…
11
А где тогда скорость превышать?
12
13
14
Angular 2
16
import { Component } from '@angular/core';
@Component({ moduleId: module.id, selector: 'project-name-app', template: ` <h1 (click)='onClick()'> {{title}} </h1> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { title = 'project-name works!'; }
17
import { Component } from '@angular/core';
@Component({ moduleId: module.id, selector: 'project-name-app', template: ` <h1 (click)='onClick()'> {{title}} </h1> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { title = 'project-name works!'; }
18
import { Component } from '@angular/core';
@Component({ moduleId: module.id, selector: 'project-name-app', template: ` <h1 (click)='onClick()'> {{title}} </h1> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { title = 'project-name works!'; }
Angular 2, Angular 2… нас и [НАШ_FRAMEWORK]
неплохо кормит
19
20
А что значит «скорость»?
21
Скорость загрузки
22
Скорость загрузки
Размер
23
Скорость загрузки
Размер
LazyLoading
24
Скорость загрузки
Скорость работы
Размер
LazyLoading
25
Скорость загрузки
Скорость работы
Размер
LazyLoading
Обьем работы
26
Скорость загрузки
Скорость работы
Размер
LazyLoading
Обьем работы Производительность
27
Скорость загрузки
Скорость работы
Размер
LazyLoading
Обьем работы Производительность
Память
28
Скорость загрузки
Скорость работы
Размер
LazyLoading
Обьем работы
Многопоточность
Производительность
Память
29
Скорость загрузки
Скорость работы
Размер
LazyLoading
Обьем работы
Многопоточность
Производительность
Память
30
Скорость работы
31
https://github.com/krausest/js-framework-benchmark
https://github.com/mathieuancelin/js-repaint-perfs
32
33
Кол-во перерисовок в секунду (больше лучше)
Angular 1
Angular 2
React
Elm
0 9 18 27 36
34
Наша цель … 90 RR
35
Кол-во перерисовок в секунду (больше лучше)
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
36
Старая версия Angular 2
37
Alpha 44
38
Alpha 44 —> v2.1.2
39
Alpha 44
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
40
v2.1.2
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
41
v2.1.2
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
42
На самом деле все просто…
43
Angular 2 Performance Checklist
44
import {enableProdMode} from '@angular/core';
enableProdMode();
45
300% в EdgeenableProdMode()
46
Alpha 44
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
47
v2.1.2 + enableProdMod()
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
48
function getData(keepIdentity) { var oldData = data; if (!keepIdentity) { // reset for each tick data = []; for (var i = 1; i <= ENV.rows; i++) { data.push({ … }); data.push({ … }); } } }
49
@Page({ template: ` <div *ngFor="let post of posts;trackBy:identify"> {{post.data}} </div> ` }) export class SomeConponent { identify(index,item){ return post.id } }
50
@Page({ template: ` <div *ngFor="let post of posts;trackBy:identify"> {{post.data}} </div> ` }) export class SomeConponent { identify(index,item){ return post.id } }
51
v2.1.2 + enableProdMod()
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
52
trackBy
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
53
AOTAhead Of Time template compilation
54
55
56
Angular CLI
ng serve ——aotng build ——aot
57
trackBy
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
58
AOT
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
59
WebWorkers
60
import {bootstrapWorkerUi} from '@angular/platform-webworker'; import {enableProdMode} from '@angular/core';
export function main() { enableProdMode(); bootstrapWorkerUi('loader.js'); }
61
import {bootstrapWorkerUi} from '@angular/platform-webworker'; import {enableProdMode} from '@angular/core';
export function main() { enableProdMode(); bootstrapWorkerUi('loader.js'); }
62
@NgModule({ imports: [WorkerAppModule], bootstrap: [AppComponent], declarations: [AppComponent] }) class WebWorkerModule {}
export function main() { enableProdMode(); platformWorkerAppDynamic().bootstrapModule(WebWorkerModule); }
63
@NgModule({ imports: [WorkerAppModule], bootstrap: [AppComponent], declarations: [AppComponent] }) class WebWorkerModule {}
export function main() { enableProdMode(); platformWorkerAppDynamic().bootstrapModule(WebWorkerModule); }
64
AOT
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
65
webWorkers
Angular 2
Target
0 10 20 30 40 50 60 70 80 90
66
67
Кол-во перерисовок в секунду (больше лучше)
Angular 1
Angular 2
React
Elm
0 10 20 30 40 50 60 70 80 90
68
Еще раз• enableProd() • trackBy • AOT • WebWorkers
69
Заглянем под капот
70
Scott Hanselman
71
ZoneJs
72
73
const http = require('http');
const hostname = '127.0.0.1'; const port = 3000;
const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World'); });
server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); });
74
75
process.on('uncaughtException', (err) => { console.log(`Caught exception: ${err}`); });
76
77
Zone.current.fork({}).run(function () { Zone.current.inTheZone = true; setTimeout(someCallback, 0); });
function someCallback() { console.log(Zone.current.inTheZone); }
setTimeout(someCallback, 0);
78
Zone.current.fork({}).run(function () { Zone.current.inTheZone = true; setTimeout(someCallback, 0); });
function someCallback() { console.log(Zone.current.inTheZone); }
setTimeout(someCallback, 0);
79
Zone.current.fork({}).run(function () { Zone.current.inTheZone = true; setTimeout(someCallback, 0); });
function someCallback() { console.log(Zone.current.inTheZone); }
setTimeout(someCallback, 0);
80
Zone.current.fork({}).run(function () { Zone.current.inTheZone = true; setTimeout(someCallback, 0); });
function someCallback() { console.log(Zone.current.inTheZone); }
setTimeout(someCallback, 0);
81
Zone.current.fork({}).run(function () { Zone.current.inTheZone = true; setTimeout(someCallback, 0); });
function someCallback() { console.log(Zone.current.inTheZone);//TRUE }
setTimeout(someCallback, 0);
82
Zone.current.fork({}).run(function () { Zone.current.inTheZone = true; setTimeout(someCallback, 0); });
function someCallback() { console.log(Zone.current.inTheZone); }
setTimeout(someCallback, 0);
83
Zone.current.fork({}).run(function () { Zone.current.inTheZone = true; setTimeout(someCallback, 0); });
function someCallback() { console.log(Zone.current.inTheZone);//FALSE }
setTimeout(someCallback, 0);
84
Change Detection
85
86
87
88
89
90
// very simplified version of actual source class ApplicationRef {
changeDetectorRefs:ChangeDetectorRef[] = [];
constructor(private zone: NgZone) { this.zone.onTurnDone .subscribe(() => {
this.zone.run(() => this.tick() });
}
tick() { this.changeDetectorRefs .forEach((ref) => ref.detectChanges()); } }
91
// very simplified version of actual source class ApplicationRef {
changeDetectorRefs:ChangeDetectorRef[] = [];
constructor(private zone: NgZone) { this.zone.onTurnDone .subscribe(() => {
this.zone.run(() => this.tick() });
}
tick() { this.changeDetectorRefs .forEach((ref) => ref.detectChanges()); } }
92
// very simplified version of actual source class ApplicationRef {
changeDetectorRefs:ChangeDetectorRef[] = [];
constructor(private zone: NgZone) { this.zone.onTurnDone .subscribe(() => {
this.zone.run(() => this.tick() });
}
tick() { this.changeDetectorRefs .forEach((ref) => ref.detectChanges()); } }
93
// very simplified version of actual source class ApplicationRef {
changeDetectorRefs:ChangeDetectorRef[] = [];
constructor(private zone: NgZone) { this.zone.onTurnDone .subscribe(() => {
this.zone.run(() => this.tick() });
}
tick() { this.changeDetectorRefs .forEach((ref) => ref.detectChanges()); } }
94
95
@Component({ template: '<v-card [vData]="vData"></v-card>' }) class VCardApp {
constructor() { this.vData = { name: 'Christoph Burgdorf', email: '[email protected]' } }
changeData() { this.vData.name = 'Pascal Precht'; } }
96
@Component({ template: ` <h2>{{vData.name}}</h2> <span>{{vData.email}}</span> ` }) class VCardCmp { @Input() vData; }
97
@Component({ template: '<v-card [vData]="vData"></v-card>' }) class VCardApp {
constructor() { this.vData = { name: 'Christoph Burgdorf', email: '[email protected]' } }
changeData() { this.vData = { name: 'Pascal Precht' }; } }
98
@Component({ template: ` <h2>{{vData.name}}</h2> <span>{{vData.email}}</span> `, changeDetection: ChangeDetectionStrategy.OnPush }) class VCardCmp { @Input() vData; }
99
100
Управляем Zone и CD
101
constructor(private zone: NgZone) {}
102
processOutsideAngularZone() { this.progress = 0; this.zone.runOutsideAngular(() => { this.increaseProgress(() => { this.zone.run(() => { console.log('Outside Done!'); }); }); }); }
103
processOutsideAngularZone() { this.progress = 0; this.zone.runOutsideAngular(() => { this.increaseProgress(() => { this.zone.run(() => { console.log('Outside Done!'); }); }); }); }
104
constructor(private cd: ChangeDetectorRef) {}
105
ngOnInit() { this.addItemStream.subscribe(() => { this.counter++; // application state changed this.cd.markForCheck(); // marks path }) } }
106
А можно как-то попроще?
107
Redux
108
ng2-redux ngrx/store
109
Mobx
110
ng2-mobx
111
112
Улучшаем Perceived Performance
•Увеличивая реальную производительность
113
Улучшаем Perceived Performance
•Увеличивая реальную производительность •Замедляя реальную производительность
114
Улучшаем Perceived Performance•Увеличивая реальную производительность •Замедляя реальную производительность •Грамотно перераспределяя нагрузку и ресурсы
115
116
FRPfunctional reactive programming
117
this.form.valueChanges .filter((value) => this.form.valid) .switchMap((value) => { return http.post(‘/api’, value) });
118
this.form.valueChanges .debounce(500) .filter((value) => this.form.valid) .switchMap((value) => { return http.post(‘/api’, value) });
119
this.form.valueChanges .debounce(500) .distinctUntilChanged() .filter((value) => this.form.valid) .switchMap((value) => { return http.post(‘/api’, value) });
120
this.form.valueChanges .debounce(500) .distinctUntilChanged() .filter((value) => this.form.valid) .switchMap((value) => { return http.post(‘/api’, value) }).retryWhen(attempts => attempts .zip(Observable.range(1, 3), (_, i) => i) .flatMap((i: number) => { return Observable.timer(i * 1000); }) ))
121
122