Pytanie Jak działa powiązanie danych w AngularJS?


Jak działa powiązanie danych w AngularJS struktura?

Nie znalazłem szczegółów technicznych ich strona. Mniej więcej jasne jest, jak to działa, gdy dane są propagowane z widoku do modelu. Ale w jaki sposób AngularJS śledzi zmiany właściwości modelu bez ustawiaczy i pobierających?

Znalazłem, że są Obserwatorzy JavaScript to może zrobić tę pracę. Ale nie są obsługiwane w Internet Explorer 6 i Internet Explorer 7. Skąd AngularJS wie, że zmieniłem na przykład poniższe i odzwierciedliłem tę zmianę w widoku?

myobject.myproperty="new value";

1803
2018-03-13 10:16


pochodzenie


Należy pamiętać, że od kątowego 1.0.0rc1 należy podać ng-model-instant (docs-next.angularjs.org/api/...), aby twój moder był zawsze na bieżąco. W przeciwnym razie zostanie zaktualizowany w przypadku rozmycia. - Sotomajor
Link Marcello jest najwyraźniej zepsuty, więc tutaj znowu jest: github.com/mhevery/angular.js/blob/master/docs/content/guide/... - riffraff
@orian, ten link jest zły. zaktualizowany do (zakładam) jest taki sam - docs.angularjs.org/guide/databinding - Kevin Meredith
Dla tych, którzy wciąż czytają to pytanie, zauważcie, że Angular 2.0 znacznie zmienił sposób, w jaki używają databinding od Angular 1.x, aby pracować z komponentami sieciowymi i rozwiązać wiele problemów w poniższych odpowiedziach. - aug


Odpowiedzi:


AngularJS zapamiętuje wartość i porównuje ją z poprzednią wartością. To podstawowe sprawdzanie brudu. Jeśli nastąpiła zmiana wartości, uruchamia zmianę zdarzenia.

The $apply() metoda, którą wywołujesz, przechodząc ze świata nieangularowego do świata AngularJS, wywołania $digest(). Podsumowanie to po prostu stare, brudne sprawdzanie. Działa na wszystkich przeglądarkach i jest całkowicie przewidywalny.

Aby przeciwdziałać sprawdzaniu brudu (AngularJS) a zmieniać słuchaczy (KnockoutJS i Backbone.js): Podczas gdy sprawdzanie brudu może wydawać się proste, a nawet nieskuteczne (zajmie to się później), okazuje się, że jest ono semantycznie poprawne przez cały czas, podczas gdy słuchacze zmiany mają wiele dziwnych przypadków narożnych i potrzebują rzeczy takich jak śledzenie zależności, aby jest bardziej semantycznie poprawny. Ignorowanie zależności KnockoutJS to sprytna funkcja problemu, którego nie ma AngularJS.

Problemy ze słuchaczami zmian:

  • Składnia jest okropna, ponieważ przeglądarki nie obsługują jej natywnie. Tak, są serwery proxy, ale we wszystkich przypadkach nie są one poprawne semantycznie i oczywiście nie ma żadnych serwerów proxy na starych przeglądarkach. Najważniejsze jest to, że pozwala na to brudne sprawdzanie POJO, podczas gdy KnockoutJS i Backbone.js zmuszają Cię do dziedziczenia po zajęciach i uzyskiwania dostępu do twoich danych przez akcesorów.
  • Zmień koalescencję. Załóżmy, że masz szereg przedmiotów. Powiedzmy, że chcesz dodać elementy do tablicy, ponieważ jesteś w pętli do dodania, za każdym razem, gdy dodajesz, uruchamiasz zdarzenia na zmianie, która jest renderowaniem interfejsu użytkownika. To bardzo źle wpływa na wydajność. To, czego chcesz, to zaktualizować interfejs tylko raz, na końcu. Zdarzenia zmiany są zbyt drobnoziarniste.
  • Zmiana słuchaczy natychmiast uruchamia setera, co stanowi problem, ponieważ detektor zmian może dalej zmieniać dane, które wywołują więcej zmian. Jest to złe, ponieważ na twoim stosie może zdarzyć się kilka zmian na raz. Załóżmy, że masz dwie tablice, które muszą być zsynchronizowane z jakiegokolwiek powodu. Możesz dodać tylko do jednego lub drugiego, ale za każdym razem, gdy dodajesz, wywołujesz zdarzenie zmiany, które teraz ma niespójny obraz świata. Jest to bardzo podobny problem do blokowania wątków, którego JavaScript unika, ponieważ każde wywołanie zwrotne wykonuje się wyłącznie i do końca. Zmień zdarzenia, łamiesz to, ponieważ setery mogą mieć dalekosiężne konsekwencje, które nie są zamierzone i nieoczywiste, co tworzy problem z wątkiem na nowo. Okazuje się, że to, co chcesz zrobić, to opóźnić wykonanie detektora i zagwarantować, że działa tylko jeden detektor naraz, stąd każdy kod może dowolnie zmieniać dane i wie, że żaden inny kod nie działa podczas tego procesu. .

A co z wydajnością?

Może się więc wydawać, że jesteśmy powolni, ponieważ sprawdzanie brudu jest nieefektywne. Tutaj musimy spojrzeć na liczby rzeczywiste, a nie tylko na teoretyczne argumenty, ale najpierw określmy pewne ograniczenia.

Ludzie to:

  • Powolny - Wszystko, co jest szybsze niż 50 ms, jest niedostrzegalne dla ludzi i dlatego może być uważane za "natychmiastowe".

  • Ograniczony - Na jednej stronie nie można pokazać więcej niż około 2000 informacji. Coś więcej niż to jest naprawdę zły interfejs użytkownika, a ludzie i tak nie mogą tego przetworzyć.

Tak więc prawdziwe pytanie brzmi: ile porównań można wykonać w przeglądarce w 50 ms? Trudno odpowiedzieć na to pytanie, ponieważ wiele czynników wchodzi w grę, ale tutaj jest przypadek testowy: http://jsperf.com/angularjs-digest/6 który tworzy 10 000 obserwatorów. W nowoczesnych przeglądarkach zajmuje to mniej niż 6 ms. Na Internet Explorer 8 zajmuje około 40 ms. Jak widać, obecnie nie jest to problemem nawet w wolnych przeglądarkach. Jest pewne zastrzeżenie: porównania muszą być proste, aby dopasować się do limitu czasu ... Niestety zbyt łatwo jest dodać powolne porównanie do AngularJS, więc łatwo jest budować wolne aplikacje, gdy nie wiesz, co robią. Ale mamy nadzieję uzyskać odpowiedź, dostarczając moduł instrumentacji, który pokaże ci, które są powolnymi porównaniami.

Okazuje się, że gry wideo i procesory graficzne używają metody "brudnego sprawdzania", szczególnie dlatego, że jest spójna. Tak długo, jak osiągają one częstotliwość odświeżania monitora (zazwyczaj 50-60 Hz, lub co 16,6-20 ms), wydajność w stosunku do tego jest marnowana, więc lepiej jest rysować więcej rzeczy, niż zwiększać FPS.


2660
2018-03-13 23:47



@Mark - tak, w KO wystarczy dodać .extend ({przepustnica: 500}), aby odczekać 500 milisekund po ostatnim zdarzeniu zmiany, zanim zacznie działać. - Daniel Earwicker
Cała ta odpowiedź jest wielka, niż "dopóki mają 50 fps, jakakolwiek wydajność ponad to jest marnowaniem, ponieważ ludzkie oko nie może tego docenić, więc lepiej jest rysować więcej rzeczy, niż uzyskiwać fps wyżej." To stwierdzenie jest całkowicie nieprawidłowe w zależności od aplikacji. Oko może z pewnością docenić ponad 50 klatek na sekundę, a jak różne problemy z wyświetlaniem VR (przeczytaj najnowsze z Johnem Carmackiem lub Michaelem Abrashem, zwłaszcza z pogawędką GDC 2013 VR tego ostatniego), 50 fps jest w rzeczywistości zbyt powolne. Poza tym twoja odpowiedź jest świetna. Po prostu nie chcę rozpowszechniania dezinformacji. - Nate Bundy
Zastanawiasz się, czy Twoja aplikacja jest podobna do Twittera lub wątku / forum z komentarzem, a implementujesz nieskończone przewijanie w oparciu o Angular, możesz uruchomić limit "2000 sztuk informacji". Pojedynczy komentarz z łatwością może zawierać kilka zmiennych dotyczących nazwiska autora, profilu img, treści, datetime itd. Również, powiedzmy, mamy gigantyczną tablicę do przechowywania wszystkich komentarzy / postów, każda brudna kontrola wymagałaby skanowania tej tablicy, am Mam rację? Spowoduje to, że przeglądarka będzie nieco opóźniona, co jest niekorzystne dla użytkownika. Co sugerujesz w tym przypadku, aby zapewnić rozsądną wydajność? - Lucas
Oświadczenie można z łatwością powiedzieć na odwrót, ponieważ "Brudne sprawdzanie jest sprytną cechą problemu, którego nie ma nokaut". ES6 używa obserwowalnych i kątowych pozbywa się brudnego sprawdzania. Prawdziwy świat dogonił tę odpowiedź i pokazał, że jest fałszywa. - conical
"Wszystko, co jest szybsze niż 50 ms, jest niedostrzegalne dla ludzi" nie jest prawdą. Podczas testów stwierdziliśmy, że nasi klienci mogą z łatwością odróżnić opóźnienia aktualizacji 50 ms (20 fps) i 16,6 ms opóźnienia aktualizacji (60 fps). Sceny działające z poprzednią szybkością stale uzyskują gorsze ogólne oceny "jak to się czuje" nawet wtedy, gdy ludzie nie świadomie zarejestrowali framerate. - Crashworks


Misko dał już doskonały opis tego, jak działają powiązania danych, ale chciałbym dodać mój pogląd na problem z wydajnością związany z powiązaniem danych.

Jak stwierdził Misko, około 2000 wiązań pojawia się tam, gdzie zaczynają się pojawiać problemy, ale nie powinieneś mieć więcej niż 2000 informacji na stronie. Może to być prawda, ale nie każde wiązanie danych jest widoczne dla użytkownika. Po rozpoczęciu budowy dowolnego widżetu lub siatki danych z dwukierunkowym wiązaniem można z łatwością hit 2000 wiązań, bez złego ux.

Rozważmy na przykład pole wyboru, w którym można wpisać tekst, aby przefiltrować dostępne opcje. Ten rodzaj kontroli może mieć ~ 150 pozycji i nadal będzie bardzo użyteczny. Jeśli ma jakąś dodatkową funkcję (na przykład konkretną klasę na aktualnie wybranej opcji), zaczynasz otrzymywać 3-5 wiązań dla każdej opcji. Umieść trzy z tych widżetów na stronie (np. Jeden, aby wybrać kraj, drugi, aby wybrać miasto w danym kraju, a trzeci, aby wybrać hotel), a Ty jesteś już pomiędzy 1000 a 2000 wiązaniami.

Lub rozważ kratkę danych w korporacyjnej aplikacji internetowej. 50 wierszy na stronę nie jest nieuzasadnione, z których każda może mieć 10-20 kolumn. Jeśli zbudujesz to za pomocą ng-powtórzeń i / lub będziesz mieć informacje w niektórych komórkach, które używają niektórych powiązań, możesz zbliżyć się do 2000 wiązań tylko z tą siatką.

Uważam, że to jest olbrzymi problem podczas pracy z AngularJS, a jedynym rozwiązaniem, jakie udało mi się znaleźć do tej pory, jest zbudowanie widżetów bez użycia dwukierunkowego wiązania, zamiast tego użycie ngOnce, deregistering watchers i podobnych trików lub skonstruowanie dyrektyw, które budują DOM za pomocą jQuery i Manipulacja DOM. Czuję, że to właśnie w ten sposób pokonuje cel użycia Angulara.

Chciałbym usłyszeć sugestie na temat innych sposobów radzenia sobie z tym, ale może powinienem napisać własne pytanie. Chciałem wyrazić to w komentarzu, ale okazało się to zbyt długie, aby to ...

TL; DR 
Powiązanie danych może powodować problemy z wydajnością na złożonych stronach.


308
2017-08-22 13:28



Tak, mam to drugie. Naszym głównym zadaniem aplikacji jest wyświetlanie połączeń między różnymi podmiotami. Dana strona może mieć 10 sekcji. Każda sekcja ma stół. Każda tabela ma 2-5 filtrów nagłówkowych. Każda tabela ma 2-5 kolumn, każda z 10 rzędami. Bardzo szybko natrafiamy na problemy z perfekcją i opcje "podobnych lew". - Scott Silvi
Czy można powiedzieć, że Angular to nie tylko powiązanie danych, a niektóre aplikacje mogą nie chcieć korzystać z tej funkcji z dokładnie tych powodów, o których inni mówili? Myślę, że podejście DI i modułowość jest sama warta; posiadanie magicznego automatycznego wiązania jest przyjemne, ale w każdej istniejącej implementacji ma kompromisy wydajności. Sposób Angulara jest zdecydowanie lepszy w przypadku większości aplikacji internetowych CRUD, a ludzie po prostu uderzają w ścianę, próbując doprowadzić do skrajności. Byłoby miło mieć alternatywną metodę słuchania zdarzeń obsługiwaną, ale może to jest zasadniczo zbyt skomplikowane dla pojedynczego frameworka? - Jason Boyd
Angular ma teraz jeden sposób i bind-once databinding, aby pomóc w tym problemie. Ponadto ma teraz indeksy dla źródła repeatera, które pozwala modyfikować listę bez odbudowywania dom dla całej zawartości. - Mithon
@MW. Szczerze mówiąc, myślałem, że bind-once był w jądrze. Ale wygląda na to, że tak nie jest. To jest coś, co możesz zrobić, pisząc własne dyrektywy, w zasadzie łącząc rzeczy bez ich oglądania. Istnieje jednak dla niego mod ux: github.com/pasvaz/bindonce - Mithon
Przyszły okrzyk z przyszłości dla każdego, kto to czyta: jeden raz wiążący jest teraz główną cechą w Angular v1.3, przeczytaj więcej tutaj: docs.angularjs.org/guide/expression - Nobita


Przez brudne sprawdzanie $scope obiekt

Angular utrzymuje prostotę array obserwatorów w $scope obiekty. Jeśli przejrzysz jakieś $scope okaże się, że zawiera array nazywa $$watchers.

Każdy obserwator to object który zawiera między innymi

  1. Wyrażenie, które obserwator monitoruje. To może być po prostu attribute imię lub coś bardziej skomplikowanego.
  2. Ostatnia znana wartość wyrażenia. Można to sprawdzić w oparciu o bieżącą wyliczoną wartość wyrażenia. Jeśli wartości różnią się, obserwator wywoła funkcję i oznaczy ją $scope jak brudne.
  3. Funkcja, która zostanie wykonana, jeśli obserwator jest brudny.

Jak definiowani są obserwatorzy

Istnieje wiele różnych sposobów definiowania obserwatora w AngularJS.

  • Możesz jawnie $watch na attribute na $scope.

    $scope.$watch('person.username', validateUnique);
    
  • Możesz umieścić {{}} interpolacja w twoim szablonie (watcher zostanie utworzony dla ciebie na bieżącym $scope).

    <p>username: {{person.username}}</p>
    
  • Możesz poprosić o dyrektywę taką jak ng-model aby zdefiniować obserwatora dla ciebie.

    <input ng-model="person.username" />
    

The $digest Cykl sprawdza wszystkich obserwatorów przed ich ostatnią wartością

Kiedy wchodzimy w interakcję z AngularJS poprzez normalne kanały (ng-model, ng-repeat, itp.), Dyrektywa będzie wyzwalać cykl skracania.

Cykl trawienia to pierwsze przejście z głębokości $scope i wszystkie jego dzieci. Dla każdego $scope  object, iterujemy nad jego $$watchers  array i oceniaj wszystkie wyrażenia. Jeśli nowa wartość wyrażenia różni się od ostatniej znanej wartości, wywoływana jest funkcja watcher. Ta funkcja może rekompilować część DOM, przelicz wartość na $scope, wywołaj AJAX  requestwszystko, czego potrzebujesz.

Każdy zakres jest przesuwany, a każde wyrażenie zegarka oceniane i sprawdzane pod kątem ostatniej wartości.

Jeśli obserwator zostanie uruchomiony, funkcja $scope jest brudny

Jeśli uruchomi się watcher, aplikacja wie, że coś się zmieniło, a $scope jest oznaczony jako brudny.

Funkcje Watcher mogą zmieniać inne atrybuty $scope lub na rodzica $scope. Gdyby jeden $watcher funkcja została uruchomiona, nie możemy zagwarantować, że nasza druga $scopes są nadal czyste, więc ponownie wykonujemy cały cykl trawienia.

Dzieje się tak dlatego, że AngularJS ma dwukierunkowe wiązanie, więc dane można przekazać z powrotem $scopedrzewo. Możemy zmienić wartość na wyższą $scope który został już strawiony. Być może zmienimy wartość na $rootScope.

Jeśli $digest jest brudny, wykonujemy całość $digest powtórzyć cykl

Ciągle przechodzimy przez pętlę $digest cykl, aż do zakończenia cyklu trawienia (wszystkie $watch wyrażenia mają taką samą wartość jak w poprzednim cyklu) lub osiągamy limit trawienia. Domyślnie ten limit wynosi 10.

Jeśli osiągniemy limit trawienia, AngularJS zgłosi błąd w konsoli:

10 $digest() iterations reached. Aborting!

Podsumowanie jest trudne dla maszyny, ale łatwe dla programisty

Jak widać, za każdym razem, gdy coś się zmieni w aplikacji AngularJS, AngularJS sprawdzi każdy obserwator w $scope hierarchia, aby zobaczyć, jak odpowiedzieć. Dla programisty jest to ogromne zwiększenie produktywności, ponieważ teraz nie trzeba pisać prawie żadnego kodu, AngularJS zauważy tylko, czy wartość się zmieniła, a reszta aplikacji będzie zgodna ze zmianą.

Z perspektywy maszyny jest to jednak szalenie nieefektywne i spowolni naszą aplikację, jeśli stworzymy zbyt wielu obserwatorów. Misko przytoczył liczbę około 4000 obserwatorów, zanim Twoja aplikacja będzie działać wolno w starszych przeglądarkach.

Ten limit jest łatwy do osiągnięcia, jeśli ng-repeat na dużym JSON  array na przykład. Można przeciwdziałać temu przy użyciu takich funkcji jak jednorazowe wiązanie, aby skompilować szablon bez tworzenia obserwatorów.

Jak uniknąć tworzenia zbyt wielu obserwatorów

Za każdym razem, gdy użytkownik wejdzie w interakcję z Twoją aplikacją, każdy obserwator w Twojej aplikacji zostanie oceniony co najmniej raz. Dużą częścią optymalizacji aplikacji AngularJS jest zmniejszenie liczby obserwatorów $scope drzewo. Jednym z łatwych sposobów na to jest z jeden raz wiążący.

Jeśli masz dane, które rzadko się zmieniają, możesz powiązać je tylko raz, używając składni ::, na przykład:

<p>{{::person.username}}</p>

lub

<p ng-bind="::person.username"></p>

Wiązanie zostanie wywołane tylko wtedy, gdy szablon zawierający zostanie wyrenderowany, a dane wczytane do $scope.

Jest to szczególnie ważne, gdy masz ng-repeat z wieloma przedmiotami.

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>

142
2018-06-02 12:31



Nie zgadzam się, że odpowiedź powinna znajdować się na górze; istnieje różnica między wiedzą o czymś a pisaniem odpowiedniej / szczegółowej odpowiedzi na konkretne pytanie. Są lepsze sposoby na zdobycie uznania. Tak czy inaczej .. - user2864740
Nie wątpię, że to prawda, ale pytania i odpowiedzi na pytania odpowiadają :) - user2864740
Dobra odpowiedź na pytanie, jak zachowuje się brudna kratka i co właściwie ocenia, jedna rzecz nie była zbyt jasna w odpowiedzi Misko. - bitstrider
Znakomita i szczegółowa odpowiedź. @superluminary, dzięki za taką odpowiedź. Co więcej, po przeczytaniu tej odpowiedzi doszedłem do punktu, w którym nie możemy dodawać nie idempotentnego wyrażenia jako obserwowanego wyrażenia. - Mangu Singh Rajpurohit
To powinna być najlepsza odpowiedź - Alexandre Bourlier


To jest moje podstawowe zrozumienie. To może być źle!

  1. Przedmioty są obserwowane przez przekazanie funkcji (zwrócenie rzeczy, która ma być wykonana) oglądałem) do $watch metoda.
  2. Zmiany obserwowanych elementów muszą być dokonywane w ramach bloku kodu zapakowane przez $apply metoda.
  3. Na końcu $apply  $digest metoda jest wywoływana, co idzie przez każdy z zegarków i czeków, aby sprawdzić, czy od tego czasu się zmieniły Ostatni raz $digest biegł.
  4. Jeśli zostaną znalezione jakiekolwiek zmiany, wówczas odwołanie jest wywoływane ponownie, dopóki wszystkie zmiany się nie ustabilizują.

W normalnym rozwoju składnia wiążąca dane w kodzie HTML mówi kompilatorowi AngularJS, aby utworzyć dla ciebie zegarki, a metody kontrolera są uruchamiane wewnątrz $apply już. Tak więc dla autora aplikacji wszystko jest przejrzyste.


77
2018-03-13 21:01



kiedy aktywowana jest metoda zastosowania? - numan salati
@EliseuMonar Pętla digest działa w wyniku jakiegoś zdarzenia lub wywołania $ apply (), nie jest nazywana okresowo w oparciu o timer. widzieć Jak działa funkcja $ zegarka AngularJS? i jak działa wiązanie i trawienie w AngularJS? - remi
@remi, nie przejmuję się ostatnią wersją AngularJS. Czy już używają serwerów proxy lub Object.observe? Jeśli nie, to wciąż są w erze brudnej kontroli, która buduje pętlę czasową, aby sprawdzić, czy atrybuty modelu uległy zmianie. - Eliseu Monar dos Santos
Czytałem, że ten skrót będzie działał maksymalnie dziesięć razy sitepoint.com/understanding-angulars-apply-digest - user137717


Przez chwilę zastanawiałem się nad tym. Bez seterów w jaki sposób AngularJS zauważ zmiany w $scope obiekt? Czy to sonduje?

Co to właściwie robi, to: każde "normalne" miejsce, w którym modyfikujesz model, zostało już wywołane z odwagi AngularJS, więc automatycznie dzwoni $apply dla ciebie po uruchomieniu kodu. Powiedz, że twój kontroler ma metodę, która jest podłączona do ng-click na jakimś elemencie. Bo AngularJS druty wywoływanie tej metody razem dla ciebie, ma szansę zrobić $apply w odpowiednim miejscu. Podobnie, w przypadku wyrażeń, które pojawiają się bezpośrednio w widokach, są one wykonywane przez AngularJS więc robi to $apply.

Kiedy dokumentacja mówi o konieczności połączenia $apply ręcznie dla kodu na zewnątrz AngularJS, mówi o kodzie, który po uruchomieniu nie pochodzi od AngularJS się w stosie wywołań.


57
2017-09-03 17:45





Wyjaśnianie za pomocą zdjęć:

Wiązanie danych wymaga mapowania

Odniesienie w zakresie nie jest dokładnie odniesieniem w szablonie. Kiedy dane wiążą dwa obiekty, potrzebujesz trzeciego, który nasłuchuje pierwszego i modyfikuje drugi.

enter image description here

Tutaj, kiedy modyfikujesz <input>, dotykasz data-ref3. A klasyczny mechanizm związany z danymi zostanie zmieniony data-ref4. A więc jak inni {{data}} wyrażenia będą się poruszać?

Zdarzenia prowadzą do $ digest ()

enter image description here

Angular utrzymuje a oldValue i newValue każdego wiązania. I po każdym Zdarzenie kątowe, sławny $digest() loop sprawdzi listę obserwacyjną, aby sprawdzić, czy coś się zmieniło. Te Zdarzenia kątowe są ng-click, ng-change, $http zakończone ... $digest() będzie pętla tak długo jak każda oldValue różni się od newValue.

Na poprzednim zdjęciu zauważy, że zmieniono dane-ref1 i data-ref2.

Wnioski

To trochę jak jajko i kurczak. Nigdy nie wiadomo, kto zaczyna, ale mam nadzieję, że działa przez większość czasu zgodnie z oczekiwaniami.

Druga kwestia to to, że możesz łatwo zrozumieć wpływ głębokości prostego wiązania pamięci i procesora. Mam nadzieję, że komputery stacjonarne są na tyle grube, żeby sobie z tym poradzić. Telefony komórkowe nie są tak silne.


29
2018-05-20 13:33





Oczywiście nie ma okresowego sprawdzania Scope czy jest jakakolwiek zmiana w Obiektach do niej dołączonych. Nie wszystkie obiekty dołączone do teleskopu są obserwowane. Zakres prototypowo utrzymuje a Obserwatorzy $$ . Scope tylko iteruje przez to $$watchers gdy $digest jest nazywany .

Angular dodaje obserwatora do obserwatorów $$ dla każdego z nich

  1. {{expression}} - W szablonach (i gdziekolwiek indziej, gdzie występuje wyrażenie) lub kiedy definiujemy model ng.
  2. $ scope. $ watch ('expression / function') - W twoim kodzie JavaScript możemy po prostu dołączyć obiekt zakresu, który można oglądać pod kątem.

$ watch funkcja przyjmuje trzy parametry:

  1. Pierwszy to funkcja obserwatora, która właśnie zwraca obiekt lub możemy po prostu dodać wyrażenie.

  2. Druga to funkcja detektora, która zostanie wywołana, gdy nastąpi zmiana obiektu. Wszystkie rzeczy, takie jak zmiany DOM zostaną zaimplementowane w tej funkcji.

  3. Trzeci jest parametrem opcjonalnym, który przyjmuje wartość logiczną. Jeśli jego prawdziwa, kątowa głębia obserwuje obiekt i czy jego fałszywy kątowy po prostu wykonuje odniesienie obserwując obiekt.     Szorstka implementacja zegarka $ wygląda tak

Scope.prototype.$watch = function(watchFn, listenerFn) {
   var watcher = {
       watchFn: watchFn,
       listenerFn: listenerFn || function() { },
       last: initWatchVal  // initWatchVal is typically undefined
   };
   this.$$watchers.push(watcher); // pushing the Watcher Object to Watchers  
};

W Angular jest interesująca rzecz zwana Cyklem Digest. Cykl $ digest zaczyna się w wyniku połączenia z $ scope. $ Digest (). Załóżmy, że model $ scope został zmieniony w funkcji obsługi za pomocą dyrektywy ng-click. W takim przypadku AngularJS automatycznie uruchamia cykl $ digest przez wywołanie $ digest (). Oprócz ng-click, istnieje kilka innych wbudowanych dyrektyw / usług, które pozwalają na zmianę modeli (np. Model ng, timeout, itp.) i automatycznie uruchamia cykl $ digest. Wstępna implementacja $ digest wygląda tak.

Scope.prototype.$digest = function() {
      var dirty;
      do {
          dirty = this.$$digestOnce();
      } while (dirty);
}
Scope.prototype.$$digestOnce = function() {
   var self = this;
   var newValue, oldValue, dirty;
   _.forEach(this.$$watchers, function(watcher) {
          newValue = watcher.watchFn(self);
          oldValue = watcher.last;   // It just remembers the last value for dirty checking
          if (newValue !== oldValue) { //Dirty checking of References 
   // For Deep checking the object , code of Value     
   // based checking of Object should be implemented here
             watcher.last = newValue;
             watcher.listenerFn(newValue,
                  (oldValue === initWatchVal ? newValue : oldValue),
                   self);
          dirty = true;
          }
     });
   return dirty;
 };

Jeśli używamy JavaScript setTimeout () Aby zaktualizować model zakresu, Angular nie ma możliwości sprawdzenia, co możesz zmienić. W tym przypadku naszym obowiązkiem jest ręczne wywołanie metody $ apply (), która uruchamia cykl $ digest. Podobnie, jeśli masz dyrektywę, która konfiguruje detektor zdarzeń DOM i zmienia niektóre modele w funkcji obsługi, musisz wywołać funkcję $ apply (), aby upewnić się, że zmiany zostaną wprowadzone. Główną ideą $ apply jest to, że możemy wykonać jakiś kod, który nie jest świadomy Angulara, że ​​kod nadal może zmieniać rzeczy w zakresie. Jeśli zawiniemy ten kod w $ apply, zajmie się on wywoływaniem $ digest (). Nieostrożna implementacja $ apply ().

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};

19
2018-05-22 18:18





AngularJS mechanizm wiązania danych za pomocą trzech potężnych funkcji: $ watch (),$ digest ()i $ apply (). W większości przypadków AngularJS wywoła funkcję $ scope. $ Watch () i $ scope. $ Digest (), ale w niektórych przypadkach może być konieczne ręczne wywołanie tych funkcji w celu aktualizacji nowymi wartościami.

$ watch () : -

Ta funkcja służy do obserwowania zmian w zmiennej w polu $ scope.   Akceptuje trzy parametry: wyrażenie, słuchacz i obiekt równości,   gdzie detektor i obiekt równości są parametrami opcjonalnymi.

$ digest () -

Ta funkcja przechodzi przez wszystkie zegarki w obiekcie $ scope,   i jego obiekty podrzędne $ scope
     (jeśli ma jakiekolwiek). Kiedy $ digest () iteruje   na zegarkach sprawdza, czy ma wartość wyrażenia   zmienione. Jeśli wartość się zmieniła, AngularJS wywoła słuchacza za pomocą   nowa wartość i stara wartość. Wywoływana jest funkcja $ digest ()   ilekroć AngularJS uważa, że ​​jest to konieczne. Na przykład po przycisku   kliknij lub po wywołaniu AJAX. Możesz mieć kilka przypadków, w których AngularJS   nie wywołuje funkcji $ digest () dla ciebie. W takim przypadku musisz   zadzwoń sam.

$ apply () -

Angular do auto-magicznie aktualizuje tylko te zmiany modelu, które są   w kontekście AngularJS. Kiedy zmieniasz w dowolnym modelu poza   kontekst kątowy (np. zdarzenia DOM przeglądarki, setTimeout, XHR lub trzeci   bibliotek partyjnych), następnie musisz poinformować Angular o zmianach przez   dzwonienie $ apply () ręcznie. Gdy zakończy się wywołanie funkcji $ apply ()   AngularJS wywołuje funkcję $ digest () wewnętrznie, więc wszystkie powiązania danych są   zaktualizowany.


12
2018-05-16 15:05



to mi pomaga - Jayani Sumudini


Zdarzyło mi się, że musiałem powiązać model danych osoby z formularzem, a to, co zrobiłem, to bezpośrednie odwzorowanie danych w formularzu.

Na przykład, jeśli model ma coś takiego:

$scope.model.people.name

Wejście kontrolne formularza:

<input type="text" name="namePeople" model="model.people.name">

W ten sposób, jeśli zmodyfikujesz wartość kontrolera obiektu, zostanie to automatycznie odzwierciedlone w widoku.

Przykład, w którym przekazałem model, jest aktualizowany z danych serwera, gdy pytasz o kod pocztowy i kod pocztowy na podstawie zapisanych ładunków listę kolonii i miast związanych z tym widokiem, i domyślnie ustaw pierwszą wartość dla użytkownika. I to działa bardzo dobrze, co się dzieje, to jest to angularJS czasami odświeżenie modelu zajmuje kilka sekund, aby to zrobić, możesz umieścić spinner podczas wyświetlania danych.


7
2017-09-18 05:57



Przeczytałem tę odpowiedź 5 razy i nadal nie rozumiem, co to znaczy. - sbedulin
Odpowiedź wydaje się dla mnie zagadką - Aman
@sbedulin LOL: p - Mohamed Sameer


  1. Jednokierunkowe powiązanie danych to podejście, w którym wartość jest pobierana z modelu danych i wstawiana do elementu HTML. Nie można zaktualizować modelu z widoku. Jest stosowany w klasycznych systemach szablonów. Te systemy wiążą dane tylko w jednym kierunku.

  2. Powiązanie danych w aplikacjach Angular to automatyczna synchronizacja danych między modelem i komponentami widoku.

Powiązanie danych pozwala traktować model jako jedno źródło prawdy w aplikacji. Widok jest zawsze projekcją modelu. Jeśli model zostanie zmieniony, widok odzwierciedla zmianę i odwrotnie.


5
2018-06-17 19:28