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.

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)

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.