www.acadevmy.it | francesco@acadevmy.it | info@acadevmy.it
Angular Day 2018
Change Detection, Zone.js ed altri mostri
15/06/2018 | Hotel San Marco - Verona
Francesco Sciuti
www.acadevmy.it | info@acadevmy.it | francesco@acadevmy.it
Cosa facciamo
Web | Mobile | DevOps | Labs | Formazione |
---|---|---|---|---|
Formazione
Training | Eventi | Talks |
---|---|---|
|
|
|
Chi Sono?
Developer per scelta e per passione,
amante di nerdaggini di ogni tipo
ed amante della condivisione del sapere!
Cosa mi piace?
Come gestire l'imbarazzo
da talk?
...ho promesso di parlarvi delle strane creature che popolano il nostro mondo di...
Supereroi!
sviluppatori Angular!
Ma di che mostri parleremo?
e chissà cos'altro...
Quali sono le ragioni per la quali
usiamo i framework?
ma la ragione principale è che...
Mantengono la UI sincronizzata con lo stato dell'applicazione
Definiamo la UI e, senza particolare sforzo, otteniamo ad ogni azione (che la necessita) un aggiornamento automatico tra UI e stato dell'applicazione
Lo stato dell’applicazione è l’insieme delle informazioni che determinano l’outputPossiamo pensare al processo di rendering delle modifiche dello stato come alla proiezione del modello di dati sull'interfaccia utente, ottenendo la rappresentazione (DOM >> HTML) di tali dati.
Le cose diventano più difficili quando i dati cambiano nel tempo...
Con gli anni sono state trovate svariate soluzioni:
60fps
È ciò che tutti desidereremmo per la nostra applicazione, ma per ottenerlo l'intero ciclo di rendering va completato in meno di 17 ms!
Change Detection
Per svolgere il suo lavoro è stato trasformato in un mostro, ma dentro di lui vive ancora una parte sana
Change Detection
È il meccanismo per il rilevamento delle modifiche.
Consiste nell'eseguire controlli tra due stati,
lo stato corrente ed il nuovo stato
Come scopo finale ha il compito di notificare al browser
eventuali modifiche del DOM, necessarie per aggiornare la vista quando i dati sono cambiati
Change Detection
Angular esegue il codice applicativo (a) durante il rilevamento modifiche (b) e notifica al browser eventuali aggiornamenti DOM necessari. Il browser aggiorna la vista (c)
Change Detection
Angular divide l'aggiornamento del modello dell'applicazione e riflette lo stato del modello nella vista in due fasi distinte:
Change Detection
Ogni applicazione è un insieme di componenti correlati insieme (da Input ed Output) per essere in grado di propagare dati (stato dell'applicazione)
La tua applicazione è strutturata in ciò che chiamiamo un albero di componenti
Change Detection
Unidirectional Data Flow
Change Detection
Unidirectional Data Flow
Change Detection
Unidirectional Data Flow
Change Detection
Ma allora cosa non va?
Se l'albero dei componenti cresce troppo...
Change Detection
Unidirectional Data Flow
Come possiamo riportarlo sulla retta via?
...che domande...chiamo Batman!
Change Detection
Unidirectional Data Flow
...dopo essermi reso conto che ha da fare mi ridomando...
Come possiamo riportarlo sulla retta via?
Change Detection
Conoscerlo un po' più a fondo
Change Detection
Le Strategie
Per sapere se la vista deve essere aggiornata Angular deve accedere al nuovo valore, confrontarlo con quello vecchio e decidere se la vista deve essere aggiornata
Change Detection
Conoscerlo un po' più a fondo
Cosa causa i cambiamenti?
click
, scroll
, submit
, ...setTimeout()
, setInterval()
Change Detection
Conoscerlo un po' più a fondo
La Change Detection è eseguita sulla View (ViewRef)
Per Angular, la View è il blocco fondamentale della Application UI
Change Detection
Conoscerlo un po' più a fondo
La View possiede uno stato e memorizza attraverso nodes le referenze al DOM.
Il property checks e l'update del DOM avvengono sotto il cofano per mezzo delle Views
Change Detection
Conoscerlo un po' più a fondo
Le operazioni chiave eseguite dal rilevamento delle modifiche sono le seguenti:
ng.profiler.timeChangeDetection();
Change Detection
Conoscerlo un po' più a fondo
La logica portante per la Change Detection risiede sul metodo checkAndUpdateView
Change Detection
Le Strategie - ChangeDetectionStrategy.Default
Ogni volta che qualcosa cambia nella nostra applicazione (come risultato di vari eventi utente, timer, XHR, promise, ecc.), la strategia predefinita esegue un rilevamento delle modifiche su tutti i componenti.
Questa tecnica è chiamata dirty check. Per sapere se la vista deve essere aggiornata, Angular deve accedere al nuovo valore, confrontarlo con quello vecchio e decidere se la vista deve essere aggiornata.
Change Detection
Le Strategie - ChangeDetectionStrategy.Default
Se scegliamo di adottare la strategia di default, è consigliabile seguire alcuni suggerimenti:
Change Detection
Le Strategie - ChangeDetectionStrategy.onPush
Impostando la strategia di rilevamento su onPush stiamo firmando un contratto con Angular che ci obbliga a lavorare con oggetti immutabili.
Change Detection
Le Strategie - ChangeDetectionStrategy.onPush
Change Detection prenderà il via solo quando:
Change Detection
Le Strategie - ChangeDetectionStrategy.onPush
Se scegliamo di adottare la strategia onPush, è consigliabile seguire alcuni suggerimenti:
Change Detection
Le Strategie - ChangeDetectionStrategy.onPush
Change Detection
ChangeDetectorRef
Angular ci offre un servizio chiamato ChangeDetectorRef, che è un riferimento al ChangeDetector iniettabile nel nostro componente
Questo servizio ci facilita la gestione a piacere del rilevatore di modifiche, che è molto utile quando utilizziamo la strategia OnPush o quando eseguiamo il codice al di fuori della zona
Change Detection
ChangeDetectorRef
detach
Quando si richiama questo metodo stiamo rimuovendo il componente (e tutti i suoi figli) dal rilevamento futuro delle modifiche nell'applicazione.
Le sincronizzazioni future tra stati componenti e modelli devono essere eseguite manualmente.
reattach
Quando si richiama questo metodo includiamo di nuovo il componente (e tutti i suoi figli) nelle future rilevazioni delle modifiche dell'applicazione.
Change Detection
ChangeDetectorRef
markForCheck
Quando invochiamo questo metodo ci assicuriamo che il rilevatore di modifiche del componente e di tutti i suoi antenati (fino alla radice del documento) saranno eseguiti nella successiva esecuzione.
Una volta rilevate le modifiche nel componente verrà restituita la strategia di OnPush.
detectChanges
Eseguirà manualmente la rilevazione delle modifiche nel componente
ed in tutti i suoi figli (una sorta di localscope).
Molto utilizzato nei componenti in cui è stato richiamato " detach ", ottenendo così un aggiornamento della vista.
Change Detection
ChangeDetectorRef
checkNoChanges
Controlla se vengono rilevate modifiche (anche ai relativi figli).
Questo metodo è usato in devmode per verificare che il rilevamento delle modifiche in esecuzione non presenti ulteriori modifiche.
Change Detection
Best Practices
Migliorare le prestazioni tende a coinvolgere l'ottimizzazione di tre aspetti principali:
Change Detection
Best Practice
Change Detection
Best Practice
Change Detection
Best Practice
Change Detection
Component Life
ngOnChanges
ngOnInit
ngDoCheck
ngAfterContentInit
ngAfterContentChecked
ngAfterViewInit
ngAfterViewChecked
ngOnDestroy
Change Detection
Component Life
constructor
vs ngOnInit
ngOnChanges
vs ngDoCheck
ngAfterContentInit
vs ngAfterViewInit
ngAfterContentChecked
vs ngAfterViewChecked
ngOnChanges
vs ngAfterViewChecked
ngOnDestroy
win! :DChange Detection
Components - Stateful/Stateless
Consideriamo pure functions le funzioni che dato uno stesso input ritorneranno sempre uno stesso output (no side-effects)
Change Detection
Components - Stateful/Stateless
Change Detection
Components - Stateful/Stateless
Zone.js
Prende il nostro posto ed intercetta tutto ciò che vuole, ma possiamo fermarlo!
Zone.js
Cosa è?
Libreria scritta dal team Angular, ispirata a DART
Un meccanismo di incapsulazione ed intercettazione delle attività asincrone nel browser
Zone.js
Cosa è?
Una zona è un contesto di esecuzione che persiste attraverso attività asincrone
e consente di osservare e controllare l'esecuzione del codice all'interno della zona
Zone.js
A che serve?
Zone.js
Come fa ad intercettare gli eventi async?
Zone.js esegue il monkey-patch delle API asincrone e le ridefinisce!
Il monkey-patch è una soluzione per estendere o modificare il software di sistema, senza alterare il codice sorgente (quindi solo sull'instanza in esecuzione)
Durante l'import di zone.js, vengono definite tutte le funzioni/variabili della core zone, richiamando la funzione Zone.__load_patch()
Zone.js
Conosciamolo un po'
In Zone esiste ha la nozione di current zone, che corrisponde all'attuale contesto di esecuzione, al quale si può fare accesso tramite lo static getter Zone.current
Zone.js
Conosciamolo un po'
Ogni zona inoltre ha i getter name
e parent
Zone.current.name
e Zone.current.parent
In Zone è inoltre presente il concetto di fork, che consente di creare nuove zone ed impostarne il diretto genitore
Ciò ci permette di associare più stack frame con una zona specificaconst zoneAC = Zone.current.fork({name: 'AC', properties: {data: 'initial'}});
Zone.js
Conosciamolo un po'
L'argomento passato al metodo fork
è chiamato
zone specification (ZoneSpec
)
Zone.js
Come gestire le zone
È possibile eseguire callbacks nelle zone (e quindi variare la current zone) con i seguenti metodi:
run
: invoca una funzione in una determinata zona.runGuarded
: come run
ma con la cattura degli erroriwrap
: produce una nuova funzione che cattura la zona in una closure che eseguirà z.runGuarded(callback)
quando invocataZone.js
Esempio
Zone.js
Hooks
Zone mantiene tutte le attività in sospeso nella task queue
onHasTask
: notifica quando qualcosa varia nella codaonScheduleTask
: eseguito ogni volta che viene rilevata un'operazione asincrona come setTimeoutonInvokeTask
: eseguito quando una callback passata a un'operazione asincrona viene eseguitaonInvoke
: notifica ogni volta che si entra in una zona eseguendo run()
Zone.js
Esempio
Zone.js
Quale è la relazione con Angular?
Angular utilizza Zone.js per creare una zona
(via NgZone) che viene utilizzata per eseguire il ciclo di Change Detection.
È un meccanismo molto conveniente per attivare automaticamente la Change Detection chiamando app.tick()
invece di farlo manualmente.
ApplicationRef.tick()
Zone.js
Come funziona NgZone?
In Angular, quando effettuiamo una chiamata a
platformBrowserDynamic().BootstrapModule(AppModule)
nel nostro main.ts, il modulo viene istanziato, ma prima viene creata un'istanza di NgZone
.
Zone.js
Come funziona NgZone?
NgZone
viene caricato Zone.js che crea una root zone ed un fork chiamato angular.tick()
dell'ApplicationRefZone.js
Come funziona NgZone?
NgZone è quindi il wrapper per dei fork di Zone:
NgZone.run()
)NgZone.runOutsideAngular()
)Zone.js
Cosa possiamo fare con NgZone?
Il servizio NgZone ci fornisce gli strumenti per determinare lo stato della zona di Angular ed eseguire codice all'interno o all'esterno di essa!
runOutsideAngular
: Ci consente di eseguire codice al di fuori del contesto di Angularrun
: Ci consente di rientrare nel contesto di AngularZone.js
Cosa possiamo fare con NgZone?
onUnstable
: Notifica che del codice è stato inserito ed è in esecuzione nella zona Angular.onMicrotaskEmpty
: Notifica quando nessun microtasks è accodato per l'esecuzione. Angular sottoscrive questo internamente evento per segnalare che dovrebbe essere eseguito il rilevamento delle modifiche.onStable
: Notifica quando è stato eseguito l'ultimo onMicroTaskEmpty, il che implica che tutte le attività sono state completate e che il rilevamento delle modifiche è avvenutoonError
: Notifica la presenza di erroriZone.js
Posso farne a meno?
Angular può funzionare correttamente senza Zone, per mezzo di una Noop Zone, che disabilita l'esecuzione della Change Detection
platformBrowserDynamic()
.bootstrapModule(AppModule, {ngZone: 'noop'});
Zone.js
Uno stack trace più dettagliato
Zone.js, tenendo traccia di tutte le nostre chiamate asincrone, può fornirci uno stack trace più dettagliato in caso di eccezione
Per farlo è necessario includere il modulo
long-stack-trace-zone nel codice
Ivy
Un nuovo mostro da conoscere
o un nuovo ammaliante alleato?
Ivy
Cos'è?
È il nuovo view engine di Angular
(pipeline e motore di rendering)
Ivy è ancora nelle prime fasi di sviluppo, ma pare che il tutto proceda a gonfie vele!
Miško Hevery e Kara Erickson (♥) hanno mostrato Ivy alla ng-conf 2018
Ivy
Cosa fa il view engine?
Il view engine analizza i componenti (e tutto il resto) e li traduce in normali files HTML e JavaScript, così che il browser possa leggerli e visualizzarli
Ivy è la terza incarnazione del view engine ed arriva dopo il compiler di ng2
ed il renderer2 di ng4 (che è quello che utilizziamo adesso)
Ivy
Perchè un nuovo engine? Perché Ivy è SFS acronimo inventato da me!
Due concetti chiave: Locality e Tree-Shaking
Ivy
Quali sono i vantaggi?
Ivy
Concetto Chiave: Locality
Ivy compila un file alla volta
Ivy
Concetto Chiave: Tree-Shaking
Rimuovere parti inutilizzate del codice!
Ivy
Tree-Shaking
import { myCoolFunction } from './other';
const myCondition = false;
if (myCondition) {
myCoolFunction();
}
Ivy
Ivy Pipeline
Google ha riscritto la pipeline di rendering rimuovendo il goffo Angular Interpreter
Invece di generare template data da interpretare, genera direttamente template instructions
(funzioni atomiche che fanno solo ciò che serve al template che hai scritto!)
Ivy
Ivy Pipeline - Angular Interpreter
Attualmente il compilatore produce dei metadati (Template Data) per definire un componente
ed i suoi elementi.
L'Interpreter utilizza questi dati per istanziare componenti ed eseguire il rilevamento delle modifiche.
Ivy
Ivy Pipeline - Angular Interpreter
//My name is {{name}}:
viewDef(0,[
elementDef(0,null,null,1,'span',...),
textDef(null,['My name is',...])
]
Ivy
Ivy Pipeline - Incremental DOM (custom)
Per produrre ed aggiornare i componenti e gli elementi vengono utilizzate istruzioni che producono direttamente nodi del DOM
(pussa via metadata!)
Quindi le istruzioni creano il componente, i nodi DOM ed eseguono il rilevamento delle modifiche!
Dall'approccio monolitico dell'interprete ci si è spostati
ad uno atomico delle istruzioni individuali.
Ivy
Ivy Pipeline - Incremental DOM (custom)
//My name is {{name}}:
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
text(1);
elementEnd();
}
// update mode
if (rf & RenderFlags.Update) {
textBinding(1, interpolation1('My name is', ctx.name));
}
Ivy
Ivy Pipeline
@Injectable >> ngInjectableDef
).
Ivy
Ivy Pipeline - Incremental DOM (custom) - Component Definition
const componentDefinition = { // ngComponentDef
type: MyApp,
selectors: [['my-app']],
>>> template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
elementEnd();
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'name', bind(ctx.name));
}
},
factory: () => new MyApp()
}
Ivy
Ivy Pipeline - Come fa ad essere utile al Tree-Shaking?
Diamo uno sguardo!
createViewNodes
vs elementStart, container, etc...
Ivy
Ivy Pipeline
Ivy supporta i seguenti decoratori:
Internamente questi trasformatori di classe sono chiamati "Compiler".
Ivy
Ivy Pipeline - Change Detection
Ivy
Ivy Pipeline - Change Detection
Internamente l'esecuzione del rilevamento delle modifiche in Ivy viene eseguita chiamando la funzione detectChanges
con il componente come argomento, e non con checkAndUpdateView
come avviene attualmente.
Ivy
Ivy Pipeline - Change Detection
Ivy
Ivy Pipeline - Change Detection
Ivy
Ivy Pipeline - Alcuni vantaggi nella Dev Experience
Ivy migliorerà la nostra esperienza di sviluppo
rimuovendo gran parte della rendering black box
Ivy
Alcune novità (ma nulla è definitivo)
Ivy
Nuova Modalità di Bootstrap
import { renderComponent } from '@angular/core'
import { AppComponent } from './app.component'
renderComponent(AppComponent)
Sarà mantenuto il bootstrap attuale: platformBrowserDynamic().bootstrapModule(AppModule)
Ivy
Quando sarà resa pubblica cosa succederà ai nostri progetti?
Nulla, si dovrebbero solo apprezzare i vantaggi che porterà con se!
...ma tranquilli...ci sarà di sicuro qualcos'altro che romperà i nostri progetti!
Ivy
Come vederlo in azione oggi?
git clone https://github.com/angular/angular.git
cd packages/core/test/bundling/todo
bazel run @yarn//:yarn
bazel run //packages/core/test/bundling/todo:devserver
:prodserver
puoi provare la build di produzione
Può essere testato tramite la proprietà enableIvy: true di angularCompilerOptions (tsconfig.json)
Ivy
Quando arriverà?
Google attualmente testa Ivy su oltre 600 prodotti
Senza vergogna alcuna!
Grazie a tutti!
Francesco Sciuti
www.acadevmy.it | info@acadevmy.it | francesco@acadevmy.it
e come nei cinecomics...la slide post credit!