Przepraszam, jeśli tutaj już udzielono odpowiedzi, ale nie mogłem znaleźć żadnego dopasowania dla naszego konkretnego scenariusza, więc proszę!
W naszym zespole programistów rozmawialiśmy o wywołaniach funkcji w szablonach kątowych. Zgodnie z ogólną zasadą zgadzamy się, że nie powinieneś tego robić. Próbowaliśmy jednak omówić, kiedy może być w porządku. Pozwól, że dam ci scenariusz.
Załóżmy, że mamy blok szablonu zawarty w ngIf, który sprawdza wiele parametrów, jak tutaj:
<ng-template *ngIf="user && user.name && isAuthorized">
...
</ng-template>
Czy byłaby znacząca różnica w wydajności w porównaniu do czegoś takiego:
Szablon:
<ng-template *ngIf="userCheck()">
...
</ng-template>
Maszynopis:
userCheck(): boolean {
return this.user && this.user.name && this.isAuthorized;
}
Podsumowując pytanie, czy ostatnia opcja miałaby znaczny koszt wydajności?
Wolelibyśmy zastosować drugie podejście w sytuacjach, w których musimy sprawdzić więcej niż 2 warunki, ale wiele artykułów online mówi, że wywołania funkcji ZAWSZE są złe w szablonach, ale czy to naprawdę problem w tym przypadku?
źródło
Odpowiedzi:
Starałem się również unikać wywołań funkcji w szablonach w jak największym stopniu, ale twoje pytanie zainspirowało mnie do szybkiego zbadania:
Dodałem inny przypadek z
userCheck()
wynikami buforowaniaPrzygotowałem demo tutaj: https://stackblitz.com/edit/angular-9qgsm9
Zaskakująco wygląda na to, że nie ma między nimi żadnej różnicy
I
I
Wygląda na to, że dotyczy to prostego sprawdzania właściwości, ale na pewno będzie różnica, jeśli chodzi o jakiekolwiek
async
akcje, na przykład pobierające, które oczekują na interfejs API.źródło
To dość uparta odpowiedź.
Korzystanie z takich funkcji jest całkowicie dopuszczalne. Sprawi, że szablony będą znacznie wyraźniejsze i nie spowoduje znacznego obciążenia. Jak powiedział wcześniej JB, stworzy również znacznie lepszą bazę do testów jednostkowych.
Myślę również, że każde wyrażenie, które masz w szablonie, zostanie ocenione jako funkcja przez mechanizm wykrywania zmian, więc nie ma znaczenia, czy masz je w szablonie, czy w logice komponentów.
Po prostu ogranicz logikę wewnątrz funkcji do minimum. Jeśli jednak jesteś ostrożny, jeśli chodzi o wpływ na wydajność, jaki może mieć taka funkcja, zdecydowanie zalecamy skorzystanie
ChangeDetectionStrategy
z niejOnPush
, co i tak jest uważane za najlepszą praktykę. Dzięki temu funkcja nie będzie wywoływana w każdym cyklu, tylko gdyInput
zmiany, jakieś zdarzenie wydarzy się w szablonie itp.(za pomocą itp., ponieważ nie znam już drugiego powodu) .
Osobiście uważam, że jeszcze przyjemniej jest użyć wzorca Observables, wtedy możesz użyć
async
potoku i tylko wtedy, gdy zostanie wysłana nowa wartość, szablon zostanie ponownie oceniony:Następnie możesz po prostu użyć w szablonie w ten sposób:
Jeszcze inną opcją byłoby użycie
ngOnChanges
, jeśli wszystkie zmienne zależne od komponentu są danymi wejściowymi i masz dużo logiki, aby obliczyć pewną zmienną szablonu (co nie jest pokazane w przypadku):Które możesz użyć w swoim szablonie w ten sposób:
źródło
Observable
strumień, dzięki czemu będzie idealnym kandydatem do drugiej opcji, którą pokazałem. Tak czy inaczej, cieszę się, że mogę dać ci wglądZ wielu powodów nie jest zalecany główny:
Aby ustalić, czy konieczne jest ponowne renderowanie userCheck (), Angular musi wykonać wyrażenie userCheck (), aby sprawdzić, czy zmieniła się jego wartość zwracana.
Ponieważ Angular nie jest w stanie przewidzieć, czy zmieniła się wartość zwracana przez userCheck (), musi wykonywać tę funkcję za każdym razem, gdy wykrywane są zmiany.
Więc jeśli wykrywanie zmian działa 300 razy, funkcja jest wywoływana 300 razy, nawet jeśli jej wartość zwrotna nigdy się nie zmienia.
Rozszerzone wyjaśnienia i więcej problemów https://medium.com/showpad-engineering/why-you-should-never-use-function-calls-in-angular-template-expressions-e1a50f9c0496
Problem pojawiający się, gdy twój komponent jest duży i bierzesz udział w wielu wydarzeniach związanych ze zmianą, jeśli komponent będzie niewielki i po prostu weźmiesz udział w kilku wydarzeniach, nie powinien stanowić problemu.
Przykład z obserwowalnymi
Następnie możesz użyć go jako obserwowalnego z potokiem asynchronicznym w swoim kodzie.
źródło
Myślę, że JavaScript został stworzony w celu, aby programista nie zauważył różnicy między wyrażeniem a wywołaniem funkcji w odniesieniu do wydajności.
W C ++ istnieje słowo kluczowe
inline
do oznaczenia funkcji. Na przykład:Dokonano tego w celu wyeliminowania wywołania funkcji. W rezultacie kompilator zastępuje wszystkie wywołania
userCheck
treścią funkcji. Powód innowacjiinline
? Wzrost wydajności.Dlatego myślę, że czas wykonania wywołania funkcji z jednym wyrażeniem jest prawdopodobnie dłuższy niż wykonanie tylko wyrażenia. Myślę jednak, że nie zauważysz różnicy w wydajności, jeśli masz tylko jedno wyrażenie w funkcji.
źródło