Detectarea schimbărilor unghiulare și strategia OnPush
Publicat: 2022-03-11Ai început să folosești Angular pentru toate proiectele tale preferate. Știți ce are de oferit Angular și cum îl puteți utiliza pentru a crea aplicații web uimitoare. Dar, există anumite lucruri despre Angular și cunoașterea lor te poate ajuta să folosești Angular mai bine pentru proiectele tale.
Fluxul de date fiind în centrul aproape tuturor lucrurilor Angular, detectarea schimbărilor este ceva ce merită să știți, deoarece vă va ajuta să urmăriți erorile mult mai ușor și vă va oferi oportunitatea de a vă optimiza în continuare aplicațiile atunci când lucrați cu un set de date complex.
În acest articol, veți afla cum Angular detectează modificările în structurile sale de date și cum le puteți face imuabile pentru a profita la maximum de strategiile de detectare a modificărilor Angular.
Detectarea modificării în Angular
Când schimbați oricare dintre modelele dvs., Angular detectează modificările și actualizează imediat vizualizările. Aceasta este detectarea schimbărilor în Angular. Scopul acestui mecanism este de a se asigura că vederile de bază sunt întotdeauna sincronizate cu modelele lor corespunzătoare. Această caracteristică de bază a Angular este ceea ce face ca cadrul să bifeze și este parțial motivul pentru care Angular este o alegere bună pentru dezvoltarea de aplicații web moderne.
Un model în Angular se poate schimba ca urmare a oricăruia dintre următoarele scenarii:
Evenimente DOM (clic, trece cu mouse-ul peste etc.)
solicitări AJAX
Temporizatoare (setTimer(), setInterval())
Schimbarea detectoarelor
Toate aplicațiile Angular sunt formate dintr-un arbore ierarhic de componente. În timpul execuției, Angular creează o clasă separată de detectoare de modificări pentru fiecare componentă din arbore, care apoi formează în cele din urmă o ierarhie de detectori de modificare similară arborelui ierarhic al componentelor.
Ori de câte ori este declanșată detectarea schimbărilor, Angular parcurge acest arbore de detectoare de schimbare pentru a determina dacă vreunul dintre ei a raportat modificări.
Ciclul de detectare a schimbării este efectuat întotdeauna o dată pentru fiecare schimbare detectată și începe de la detectorul de schimbare a rădăcinii și coboară până la capăt într-o manieră secvențială. Această alegere de proiectare secvențială este bună, deoarece actualizează modelul într-un mod previzibil, deoarece știm că datele componente pot veni doar de la părintele său.
Detectoarele de modificări oferă o modalitate de a urmări stările anterioare și actuale ale componentei, precum și structura acesteia pentru a raporta modificările la Angular.
Dacă Angular primește raportul de la un detector de modificări, îi cere componentei corespunzătoare să redea și să actualizeze DOM-ul în consecință.
Strategii de detectare a schimbărilor
Valoare vs. Tipuri de referință
Pentru a înțelege ce este o strategie de detectare a schimbărilor și de ce funcționează, trebuie mai întâi să înțelegem diferența dintre tipurile de valori și tipurile de referință în JavaScript. Dacă sunteți deja familiarizat cu modul în care funcționează, puteți sări peste această secțiune.
Pentru a începe, să revizuim tipurile de valori și tipurile de referință și clasificările acestora.
Tipuri de valori
boolean
Nul
Nedefinit
Număr
Şir
Pentru simplitate, ne putem imagina că aceste tipuri pur și simplu își stochează valoarea în memoria stivei (ceea ce din punct de vedere tehnic nu este adevărat, dar este suficient pentru acest articol). Vedeți memoria stivei și valorile acesteia în imaginea de mai jos, de exemplu.
Tipuri de referință
Matrice
Obiecte
Funcții
Aceste tipuri sunt puțin mai complicate, deoarece stochează o referință în memoria stivei, care indică valoarea lor reală în memoria heap. Puteți vedea cum funcționează împreună memoria stivă și memoria heap în exemplul de imagine de mai jos. Vedem că memoria stivei face referire la valorile reale ale tipului de referință din memoria heap.
Distincția importantă de făcut între tipurile de valori și tipurile de referință este că, pentru a citi valoarea tipului de valoare, trebuie doar să interogăm memoria stivei, dar pentru a citi valoarea unui tip de referință, trebuie mai întâi să facem interogați memoria stivei pentru a obține referința și apoi utilizați acea referință pentru a interoga memoria heap pentru a localiza valoarea tipului de referință.
Strategia implicită
După cum am afirmat mai devreme, Angular monitorizează modificările asupra modelului pentru a se asigura că surprinde toate modificările. Acesta va verifica orice diferențe între starea anterioară și starea actuală a modelului general de aplicație.

Întrebarea pe care Angular o pune în strategia implicită de detectare a modificărilor este: S-a schimbat vreo valoare în model? Dar pentru un tip de referință, putem implementa strategii astfel încât să putem pune o întrebare mai bună. Aici intervine strategia de detectare a modificărilor OnPush.
Strategia OnPush
Ideea principală din spatele strategiei OnPush se manifestă din conștientizarea că, dacă tratăm tipurile de referință ca obiecte imuabile, putem detecta dacă o valoare s-a schimbat mult mai repede. Când un tip de referință este imuabil, aceasta înseamnă că de fiecare dată când este actualizat, referința din memoria stivei va trebui să se schimbe. Acum putem verifica pur și simplu: S-a schimbat referința (în stivă) tipului de referință? Dacă da, abia atunci verificați toate valorile (pe grămada). Referiți-vă la diagramele heap anterioare ale stivei dacă acest lucru este confuz.
Strategia OnPush pune practic două întrebări în loc de una. S-a schimbat referința tipului de referință? Dacă da, atunci s-au schimbat valorile din memoria heap?
De exemplu, să presupunem că avem o matrice imuabilă cu 30 de elemente și vrem să știm dacă există modificări. Știm că, pentru a exista actualizări ale matricei imuabile, referința (pe stivă) ar trebui să se fi schimbat. Aceasta înseamnă că putem verifica inițial pentru a vedea dacă referința la matrice este diferită, ceea ce ne-ar putea salva de a mai efectua încă 30 de verificări (în grămada) pentru a determina ce element este diferit. Aceasta se numește strategia OnPush.
Deci, v-ați putea întreba, ce înseamnă să tratezi tipurile de referință ca imuabile? Înseamnă că nu setăm niciodată proprietatea unui tip de referință, ci reatribuim valoarea împreună. Vezi mai jos:
Tratarea obiectelor ca fiind mutabile:
static mutable() { var before = {foo: "bar"}; var current = before; current.foo = "hello"; console.log(before === current); // => true }Tratarea obiectelor ca fiind imuabile:
static mutable() { var before = {foo: "bar"}; var current = before; current = {foo "hello"}; console.log(before === current); // => false }Rețineți că, în exemplele de mai sus, „tratăm” tipurile de referință ca fiind imuabile prin convenție, așa că în cele din urmă încă lucrăm cu obiecte mutabile, dar doar „pretindem” că sunt imuabile.
Deci, cum implementați strategia OnPush pentru o componentă? Tot ce trebuie să faceți este să adăugați parametrul changeDetection în adnotarea lor @Component.
import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ // ... changeDetection: ChangeDetectionStrategy.OnPush }) export class OnPushComponent { // ... }Imuabil.js
Este o idee bună să impuneți imuabilitatea dacă decideți să utilizați strategia OnPush pe o componentă Angular. Aici intervine Immutable.js.
Immutable.js este o bibliotecă creată de Facebook pentru imuabilitate în JavaScript. Au multe structuri de date imuabile, cum ar fi Listă, Hartă și Stivă. În scopul acestui articol, Lista și Harta vor fi ilustrate. Pentru mai multe referințe, vă rugăm să consultați documentația oficială aici.
Pentru a adăuga Immutable.js la proiectele dvs., asigurați-vă că intrați în terminalul dvs. și rulați:
$ npm install immutable --saveDe asemenea, asigurați-vă că importați structurile de date pe care le utilizați din Immutable.js în componenta în care îl utilizați.
import {Map, List} from 'immutable';Iată cum poate fi utilizată o hartă Immutable.js:
var foobar = {foo: "bar"}; var immutableFoobar = Map(foobar); console.log(immutableFooter.get("foo")); // => barȘi, un Array poate fi folosit:
var helloWorld = ["Hello", "World!"]; var immutableHelloWorld = List(helloWorld); console.log(immutableHelloWorld.first()); // => Hello console.log(immutableHelloWorld.last()); // => World! helloWorld.push("Hello Mars!"); console.log(immutableHelloWorld.last()); // => Hello Mars!Dezavantajele utilizării Immutable.js
Există câteva dezavantaje principale discutabile ale utilizării Immutable.js.
După cum probabil ați observat, este puțin greoi să utilizați API-ul său, iar unui dezvoltator JavaScript tradițional s-ar putea să nu-i placă acest lucru. O problemă mai serioasă are de-a face cu faptul că nu puteți implementa interfețe pentru modelul dvs. de date, deoarece Immutable.js nu acceptă interfețe.
Învelire
S-ar putea să vă întrebați de ce strategia OnPush nu este strategia implicită pentru Angular. Presupun că se datorează faptului că Angular nu a vrut să forțeze dezvoltatorii JavaScript să lucreze cu obiecte imuabile. Dar asta nu înseamnă că îți este interzis să-l folosești.
Dacă acesta este ceva pe care doriți să îl folosiți în următorul dvs. proiect web, acum știți cât de ușor face Angular trecerea la o strategie diferită de detectare a schimbărilor.
