AngularJS Compile Proccess

843 views

Published on

AngularJS Compile Proccess

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
843
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
5
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

AngularJS Compile Proccess

  1. 1. ‫‪AngularJS Compile Process‬‬ ‫ההבנה איך אנגולר עובד מצריכה להבין את שלושת החלקים המרכזים של אנגולר:‬ ‫‪‬‬ ‫‪‬‬ ‫‪‬‬ ‫מנגנון ההזרקה (‪)$injector‬‬ ‫מנגנון ה-‪)$watch & $apply( Data Binding‬‬ ‫‪Directives‬‬ ‫בפוסט זה אני רוצה לנסות להסביר את תהליך יצירת ה-‪ .Directive‬יש הרבה חומר על זה באינטרנט וגם בספרים,‬ ‫אך גם לאחר קריאה שלהם הרגשתי עדיין שחסרה לי ההבנה של התמונה המלאה בנושא. לכן, החלטתי לצלול‬ ‫לתוך הקוד של אנגולר ואז לדייק בהסברים כמו למשל מה ההבדל בין ‪ Link‬ל- ‪ compile‬ומה ההבדל בין ה-‬ ‫‪ controller‬ל- ‪ .link‬על שאלות אלו ונוספות אני אנסה להסביר באמצעות תיאור והסבר של תהליך יצירת‬ ‫‪ .directive‬הפוסט מיועד לאנשים שכתבו כבר ‪ directives‬ורוצים להבין את תהליך יצירתם יותר לעומק.‬ ‫שלב 1: ‪$compile‬‬ ‫כאשר אנגולר מזהה שהדף נטען (‪ )DOM Content Loaded Event‬הוא מעביר את הדף תהליך של קומפילציה‬ ‫(‪ .)$compile‬התפקיד של הקומפילציה הינו להפוך את הדף מדף סטאטטי לדף דינאמי שמחבר בין ‪ Controllers‬ו-‬ ‫‪ Scopes‬ל- ‪ Views‬שהם בעצם קטעים של ‪ .HTML‬דף ה-‪ HTML‬הסטאטטי מכיל שני סוגים של טיפוסים שתהליך‬ ‫הקומפילציה צריך לטפל בהם: ביטויים ( {{‪ ) }}expression‬ו- ‪ .Directives‬בפוסט זה אתאר כיצד תהליך‬ ‫הקומפילציה "מתרגם" את ה-‪ Directives‬לקוד שיוצר את ה-‪ HTML‬הדינאמי.‬ ‫שלב 2: סריקת ה-‪ HTML‬בסגנון ‪DFS‬‬ ‫הפעולה הראשונה שהמתודה ‪ $compile‬מבצעת היא לסרוק את ה-‪ ,HTML‬למצוא את כל ה-‪ Directives‬ולמיין‬ ‫אותם ע"פ ה-‪ priority‬שלהם. בירידה לפרטים אנו רואים שהמתודה ‪ compile‬קוראת למתודה ‪compileNodes‬‬ ‫ברקורסיה.‬ ‫,‪function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective‬‬ ‫{ )‪previousCompileContext‬‬ ‫...//‬ ‫= ‪var compositeLinkFn‬‬ ‫,‪compileNodes( $compileNodes, transcludeFn, $compileNodes‬‬ ‫;) ‪maxPriority, ignoreDirective, previousCompileContext‬‬ ‫...//‬ ‫{ )‪return function publicLinkFn(scope, cloneConnectFn, transcludeControllers‬‬ ‫...//‬ ‫;}‬ ‫}‬ ‫קוד 1: חלק ממתודה ‪compile‬‬ ‫כדי להדגים את סדר הפעולות בחרתי דוגמאת ‪ HTML‬שמיצגת את רוב המקרים.‬ ‫>‪<div‬‬ ‫>2‪<div directive-name directive-name‬‬ ‫>3‪<div directive-name‬‬
  2. 2. Hello World... </div> </div> <div directive-name directive-name2> <div directive-name3> Hello World... </div> </div> </div> .‫ ליצוג של עץ‬HTML-‫כדי שיהיה לנו יותר קל נעביר את ה‬ 1 DIV 2 DIV 3 DIV Directive-name Directive-name Directive-name2 Directive-name2 4 DIV 5 DIV Directive-name3 Directive-name3 Hello World Hello World .‫ כפרמטר‬div1 ‫ מקבלת את‬compile ‫1. המתודה‬ .div3 -‫ ו‬div2 ‫ עם מערך של הילדים, כלומר‬compileNodes ‫ קוראת למתודה‬compile ‫. המתודה‬a for loop on child ( ‫ קוראת למתודות הבאות לכל אחד מהילדים‬compileNodes ‫. המתודה‬i :)nodes collectDirectives .1 applyDirectivesToNode .2 .‫ על הילדים של הילדים‬compileNodes .3
  3. 3. function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective, previousCompileContext) { //... for (var i = 0; i < nodeList.length; i++) { attrs = new Attributes(); directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined, ignoreDirective); nodeLinkFn = (directives.length) ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement, null, [], [], previousCompileContext) : null; //... childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !(childNodes = nodeList[i].childNodes) || !childNodes.length) ? null : compileNodes(childNodes, nodeLinkFn ? nodeLinkFn.transclude : transcludeFn); //... } //... } compileNodes ‫קוד 2: חלק ממתודה‬ :‫אוקי בואו נעצור כאן ונראה איך זה קורה בפועל‬ ‫. היא מזהה שיש עליו שני‬div2 ‫ נקראת בפעם הראשונה כאשר היא מקבלת את‬collectDirectives ‫המתודה‬ directive ‫, לא לפני שהיא מפעילה את הפונקציה שיוצרת את‬collection-‫ והיא מוסיפה אותם ל‬directives ‫ שנמצאו‬directives-‫ של כל ה‬DDO ‫ קיבלה מערך של‬compileNodes ‫). כלומר המתודה‬DDO( definition object .div2 ‫על‬ ‫ כאשר היא מעבירה את המערך‬applyDirectivesToNode ‫ קוראת למתודה‬compileNodes ‫בשלב שני המתודה‬ ‫ ילדים ( במקרה שלנו ילד‬div2-‫ "רואה" שיש ל‬applyDirectivesToNode ‫. המתודה‬div2 ‫ שהיא מצאה על‬DDO ‫של‬ .div4 ‫ עם הארגומנט‬compileNodes ‫) ולכן היא קוראת למתודה‬div4 ‫אחד‬ ‫ ומקבלים מערך עם אוביקט אחד של‬collectDirectives ‫ אנחנו שוב מבצעים‬compileNodes-‫עכשיו שחזרנו שוב ל‬ string ‫ יש רק‬div4-‫ ובגלל של‬applyDirectivesToNode ‫. את המערך נותנים למתודה‬directive-name3 ‫ של‬DDO directive- ‫ של‬DDO ‫ מתוך האוביקט של‬compile-‫ ואחרי זה ל‬template-‫) המתודה קוראת ל‬hello world( ‫בתוכו‬ .name3 :‫אם תסתכלו בקוד הדוגמא כאן, עד עכשיו הסברנו את ההדפסה של‬ 1. $compile start 2. Directive factory 1 (DDO , directive-name)
  4. 4. 3. 4. 5. 6. 7. 8. 9. Directive factory 2 (DDO, directive-name2) Directive factory 3 (DDO, directive-name3) Template 3 (DDO.template, directive-name3) Compile 3 (DDO.compile, directive-name3) Template 1 (DDO.template, directive-name) Compile 1 (DDO.compile, directive-name) Compile 2 (DDO.compile, directive-name2, have no template) :‫. מכאן שהמשך ההדפסה יהיה‬div3 ‫ וכל התהליך מתחיל שוב עם‬div2 ‫עכשיו סימנו את‬ 10. 11. 12. 13. 14. 15. Template 3 (DDO.template, directive-name3) Compile 3 (DDO.compile, directive-name3) Template 1 (DDO.template, directive-name) Compile 1 (DDO.compile, directive-name) Compile 2 (DDO.compile, directive-name2, have no template) $compile Decorator took: … ‫ הקימיים ולכן לא רואים‬DDO-‫ אלה משתמשים ב‬Directive factory-‫חשוב מאד לראות שאנחנו לא קוראים שוב ל‬ .‫ קיימים כבר‬DDO-‫ את סעיפים 4-2, כי ה‬div3 ‫בהדפסה של‬ :‫$ וסיום אנו מקבלים בגלל הקוד הבא שהוספתי‬compile ‫את הדפסה של תחילת‬ app.config(function ($provide) { $provide.decorator('$compile', function ($delegate) { var result = function ($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) { var start = new Date(); console.log("$compile start"); var link = $delegate($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext); console.log("$compile Decorator took: " + (new Date() - start) + "ms"); return link; }; return result; }); }); ‫$ כדי למדוד זמנים‬compile ‫ על‬decorator :3 ‫קוד‬
  5. 5. DDO ‫ של‬link-‫שלב 3: הפעלת פונקצית ה‬ compile ‫ (ראה קוד 1, המתודה‬scope ‫ מסתיים מקבלים פונקציה שמריצים אותה עם‬compile-‫כאשר תהליך ה‬ -‫). הפעלת הפונקציה הזו יוצרת את ה‬scope ‫ שאותה אנחנו מפעילים עם‬publicLinkFn ‫מחזירה מתודה‬ ‫ ואחרי‬compile ‫. להלן הקוד שמריץ את המתודה‬postLink ‫ ובסוף את‬preLink ‫, ואחרי זה מפעילה את‬controller .scope ‫זה את הפונקציה שחוזרת עם ארגומנט של‬ function bootstrap(element, modules) { ... var injector = createInjector(modules); injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate', function(scope, element, compile, injector, animate) { scope.$apply(function() { element.data('$injector', injector); compile(element)(scope); }); }] ); return injector; } ... } bootstrap ‫קוד 4: חלק ממתודה‬ .‫ שלנו‬HTML-‫להלן המשך ההדפסה של דוגמאת ה‬ 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. controller 1 controller 2 preLink 1 preLink 2 controller 3 preLink 3 controller 4 preLink 4 postLink 4 postLink 3 postLink 2 postLink 1 controller 1 controller 2 preLink 1 preLink 2 controller 3 preLink 3 controller 4 preLink 4 postLink 4 // div3 start
  6. 6. ‫3 ‪37. postLink‬‬ ‫2 ‪38. postLink‬‬ ‫1 ‪39. postLink‬‬ ‫שלב 4: הפעלת ה-‪apply‬‬ ‫כאשר הקוד מסיים את שלב 3 מתבצעת מתודת ה-‪ apply‬ואז מבצעים ‪ eval‬לכל ‪ ,watch‬שזה כולל את כל ה-‬ ‫‪ expression‬שיש בדף.‬ ‫שאלות:‬ ‫מה ההבדל בין המתודות ‪ compile‬ו-‪ link‬של ‪?DDO‬‬ ‫הדבר הבולט ביותר זה מתי נקראת כל מתודה. ה-‪ compile‬נקרא מיד לאחר ה-‪ template‬ולמעשה הוא יכול‬ ‫לשנות את ה-‪ template‬לפני שמתבצע עליו ה-‪ compile‬של אנגולר. לעומת זאת ה-‪ link‬מתבצע לאחר שהכול עבר‬ ‫‪ compile‬ויש גם ‪ .scope‬ב- ‪ link‬בעיקר נרשמים לאירועים של ‪ DOM‬או לשינויים ב-‪.scope‬‬ ‫מה ההבדל בין המתודות של ‪ controller‬ל-‪ link‬של ‪?DDO‬‬ ‫ה-‪ controller‬נוצר לפני ה-‪ preLink‬כלומר ה-‪ DOM Element‬עדין יכול לעבור שינויים. מכאן נובע שב-‪controller‬‬ ‫לא כותבים קוד שקשור ל-‪.DOM‬‬ ‫מיד לאחר קריאה ל-‪ controller‬קוראים ל- ‪ preLink‬שזה לפני הקריאה לילדים. כאשר הילדים סימו רק אז קוראים‬ ‫ל-‪.postLink‬‬ ‫סיכום:‬ ‫אני מקווה שהצלחתי לשפוך קצת אור על תהליך הקומפילציה של אנגולר ועל סדר הפעולות שמתרחש בזמן‬ ‫הקומפילציה. מידע נוסף אפשר למצוא בבלוג ובדף הפייסבוק.‬ ‫אשמח לשמוע פידבק ושאלות בנושא ‪‬‬

×