Jaka jest różnica między $ evalAsync i $ timeout w AngularJS?

180

Od jakiegoś czasu korzystam z AngularJS i od czasu do czasu zauważyłem potrzebę użycia $ timeout (Wydaje się, że zwykle jest to inicjalizacja wtyczki jQuery).

Ostatnio próbowałem uzyskać lepsze i bardziej dogłębne zrozumienie cyklu podsumowania i natknąłem się na funkcję $ evalAsync .

Wygląda na to, że ta funkcja daje podobne wyniki $timeout, ale nie dajesz jej opóźnienia. Za każdym razem, gdy korzystałem $timeout, było to z opóźnieniem 0, więc teraz zastanawiam się, czy powinienem był użyć $evalAsync.

Czy są jakieś zasadnicze różnice między nimi? W jakich przypadkach używałbyś jednego nad drugim? Chciałbym się lepiej dowiedzieć, kiedy użyć którego.

dnc253
źródło

Odpowiedzi:

263

Ostatnio odpowiedziałem zasadniczo na to pytanie tutaj: https://stackoverflow.com/a/17239084/215945 (ta odpowiedź prowadzi do niektórych wymian github z Misko.)

Podsumowując:

  • jeśli kod jest umieszczony w kolejce za pomocą $ evalAsync z dyrektywy , powinien zostać uruchomiony po manipulacji DOM przez Angular, ale przed renderowaniem przeglądarki
  • jeśli kod jest umieszczony w kolejce za pomocą $ evalAsync z kontrolera , powinien zostać uruchomiony, zanim DOM zostanie zmanipulowany przez Angular (i przed renderowaniem przeglądarki) - rzadko tego chcesz
  • jeśli kod jest umieszczony w kolejce za pomocą $ limitu czasu , powinien on działać po manipulacji DOM przez Angular i po renderowaniu przeglądarki (co może powodować migotanie w niektórych przypadkach)
Mark Rajcok
źródło
15
Dziękuję za wyjaśnienie. Jednej rzeczy nie jestem pewien, ale rozumiem. Dlaczego robi to różnicę, jeśli wywołujesz $ evalAsync z kontrolera lub dyrektywy? AsyncQueue nie wie, czy został zarejestrowany z kontrolera czy z dyrektywy, po prostu umieszcza go w kolejce w bieżącym zakresie. Czy ma to związek z tym, że rzeczy działają w kontrolerze w porównaniu do kontrolera? Chcę tylko zrozumieć tę część.
dnc253
@ dnc253, nie sprawdziłem kodu Angular, więc nie znam odpowiedzi na twoje (dobre) pytanie. Mam nadzieję, że ktoś inny może komentować.
Mark Rajcok
15
oznacza „z dyrektywy” oznacza „z funkcji łączenia dyrektywy”? Czy też jest tak w przypadku zachowania wykonanego metodą łącza lub kontrolera w dyrektywie?
SimplGy,
5
tak, naprawdę nie jest jasne, co oznaczają tutaj
słowa
1
@MarkRajcok, czy możesz wyjaśnić tutaj: jeśli kod jest umieszczony w kolejce za pomocą $ evalAsync z dyrektywy, powinien działać po zmanipulowaniu DOM przez Angular - czy powinien działać po tym, jak DOM został zmanipulowany przez tę dyrektywę, czy przez inne dyrektywy?
Max Koretskyi
59

W przypadku budowania złożonych aplikacji należy pamiętać, że wybór ma wpływ na wydajność. Chciałbym również uzupełnić odpowiedź Marka bardziej szczegółowymi informacjami technicznymi:

  • Limit czasu $ (oddzwanianie) będzie czekał na zakończenie bieżącego cyklu podsumowania (tj. aktualizację kątową wszystkich modeli i DOM), a następnie wykona wywołanie zwrotne - potencjalnie wpływające na model kątowy - a następnie uruchomi pełny $applyzakres $ root i przekieruje wszystko.

  • Natomiast $ evalAsync (oddzwanianie) doda oddzwonienie do bieżącego lub następnego cyklu podsumowania. Co oznacza, że ​​jeśli jesteś w cyklu podsumowania (na przykład w funkcji wywoływanej z jakiejś ng-clickdyrektywy), to nie będzie na nic czekać, kod zostanie wykonany natychmiast. Jeśli znajdujesz się w wywołaniu asynchronicznym, na przykład a setTimeout, zostanie uruchomiony nowy cykl podsumowania ( $apply).

Dlatego pod względem wydajności zawsze lepiej jest wywoływać $evalAsync, chyba że ważne jest, aby widok był aktualny przed wykonaniem kodu, na przykład, jeśli potrzebujesz dostępu do niektórych atrybutów DOm, takich jak szerokość elementów i tym podobne.

Jeśli chcesz uzyskać więcej informacji na temat rozróżnienia między $ timeout, $ evalAsync, $ digest, $ Apply, zapraszam do przeczytania mojej odpowiedzi na to drugie pytanie: https://stackoverflow.com/a/23102223/1501926

Przeczytaj także dokumentację :

$ EvalAsync nie gwarantuje, kiedy wyrażenie zostanie wykonane, tylko że:

  • wykona się po funkcji, która zaplanowała ocenę (najlepiej przed renderowaniem DOM).
  • co najmniej jeden cykl $ skrótu zostanie wykonany po wykonaniu wyrażenia.

Uwaga: jeśli ta funkcja zostanie wywołana poza cyklem $ digest, zaplanowany zostanie nowy cykl $ digest . Zaleca się jednak, aby zawsze wywoływać kod, który zmienia model w ramach wywołania $ Apply. Obejmuje to kod oceniany za pomocą $ evalAsync.

floribon
źródło
Czy możesz wyjaśnić, dlaczego $ timeout jest potrzebny, jeśli potrzebuję uzyskać dostęp do atrybutu DOM. Powiedzmy, że jeśli mam <table width = "{{x}}"> Czy funkcja podglądu ng-binda nie aktualizuje atrybutu dom w pamięci, rozumiem, że nie będzie szansy odmalować widoku, dopóki nie zakończy się cykl podsumowania.
Sridhar Chidurala,
2
@SridharChidurala, ponieważ DOM („HTML”) jest aktualizowany podczas cyklu podsumowania, musisz poczekać, aż zostanie to zrobione, zanim będzie można przeczytać poprawki. Jednak Angular tego odradza, powinieneś czytać xbezpośrednio ze swojego zakresu, a nie z DOM, więc nie musisz na nic czekać. Ponadto powinieneś lepiej używać ng-stylecss zamiast przestarzałej widthwłaściwości. Jeśli potrzebujesz dodatkowej pomocy, otwórz nowe pytanie na StackOverflow.
floribon