בפעם הראשונה שקראתי על Filter של אנגולר חשבתי שזה אחד הדברים היפים שיש באנגולר, בעיקר בגלל הפשטות שלו.
בקוד הבא אנחנו רואים דוגמא קלאסית לכוח והפשטות של Filter באנגולר.
בדוגמאות קוד זו אנחנו רואים איך אפשר לכתוב ביטוי שלוקח את רשימת השמות ומכניס אותם לפונקציה OrderBy וארגומנט שני 'name' התוצאה נכנסת לפונקציה filter וארגומנט השני הוא הערך של שדה ה- search. הערך שמוחזר מהפונקציה filter הוא רשימת השמות שתכנסת ל- ng-repeat.
בנוסף אפשר גם לכתוב custom filter ולהשתמש בהם באותו אופן.
בעיות ביצועים עם Filters:
אנגולר מעדכן את המסך כל פעם שהוא מזהה שינוי על העץ של ה- scopes ע"י בדיקה של ה- watchers שמאוחסנים על ה- scopes. בדיקה זו מתבצעת כאשר קוראים למתודה $scope.$apply(), למשל שמשתמשים ב- ng-click, ng-model, $http. למעשה כל directive שמאזין לאירוע ( למשל UI , תקשורת ) מבצע בסוף הפעלה של פונקצית $apply. כל פעם ש- directive מפעיל את $apply עושים בדיקה לכל ה- watchers שקיימים על ה- scopes כלומר מפעילים גם את הביטוי:
names| orderBy:'name'| filter:search
גם אם הערכים של ה- search וה- names לא השתנו. יותר גרוע מזה, אם אחד ה- watchers מזהה שהיה שינוי חוזרים ובודקים את כל ה- watchers שוב, כלומר גם את הביטוי של ה- filters.
סיכום הבעיה:
אם האפליקציה שלנו מתעדכנת בתדירות גבוהה, כלומר הפונקציה $apply נקראת בתדירות גבוהה, אנחנו נסבול מהפעלה מרובה של הפונקציות filters גם במקרים שבטוח שהתוצאה לא תשתנה.
פתרון:
להוציא את חישוב ה- filters מה- watchers, כלומר שהם לא יכתבו בתוך ה-HTML.
ראו קוד לדוגמא:
הסבר:
פונקציה calc רצה רק כאשר השדה ה- search או השדה names משתנה ולא כל פעם שמתבצעת פונקציה $apply.
סיכום:
השימוש ב- filters ב-HTML יצור watchers שרצים כל $apply וזה יכול ליצור לנו בעיית ביצועים, בעיקר אם התדירות של הפעלת הפונקציה $apply גבוהה וה- Filters השונים רצים על רשימות גדולות.
הפתרון לעביר את החישוב מ- HTML לקוד. הפעלת החישוב תתבצע רק כאשר שדה שיכול להשפיע על החישוב שונה.