SlideShare une entreprise Scribd logo
1  sur  6
Télécharger pour lire hors ligne
‫‪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‬‬
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
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)
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 ‫קוד‬
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
‫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‬‬

‫סיכום:‬
‫אני מקווה שהצלחתי לשפוך קצת אור על תהליך הקומפילציה של אנגולר ועל סדר הפעולות שמתרחש בזמן‬
‫הקומפילציה. מידע נוסף אפשר למצוא בבלוג ובדף הפייסבוק.‬
‫אשמח לשמוע פידבק ושאלות בנושא ‪‬‬

Contenu connexe

Plus de Eyal Vardi

Smart Contract
Smart ContractSmart Contract
Smart ContractEyal Vardi
 
Rachel's grandmother's recipes
Rachel's grandmother's recipesRachel's grandmother's recipes
Rachel's grandmother's recipesEyal Vardi
 
Performance Optimization In Angular 2
Performance Optimization In Angular 2Performance Optimization In Angular 2
Performance Optimization In Angular 2Eyal Vardi
 
Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Eyal Vardi
 
Angular 2 NgModule
Angular 2 NgModuleAngular 2 NgModule
Angular 2 NgModuleEyal Vardi
 
Upgrading from Angular 1.x to Angular 2.x
Upgrading from Angular 1.x to Angular 2.xUpgrading from Angular 1.x to Angular 2.x
Upgrading from Angular 1.x to Angular 2.xEyal Vardi
 
Angular 2 - Ahead of-time Compilation
Angular 2 - Ahead of-time CompilationAngular 2 - Ahead of-time Compilation
Angular 2 - Ahead of-time CompilationEyal Vardi
 
Routing And Navigation
Routing And NavigationRouting And Navigation
Routing And NavigationEyal Vardi
 
Angular 2 Architecture
Angular 2 ArchitectureAngular 2 Architecture
Angular 2 ArchitectureEyal Vardi
 
Angular 1.x vs. Angular 2.x
Angular 1.x vs. Angular 2.xAngular 1.x vs. Angular 2.x
Angular 1.x vs. Angular 2.xEyal Vardi
 
Angular 2.0 Views
Angular 2.0 ViewsAngular 2.0 Views
Angular 2.0 ViewsEyal Vardi
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Eyal Vardi
 
Template syntax in Angular 2.0
Template syntax in Angular 2.0Template syntax in Angular 2.0
Template syntax in Angular 2.0Eyal Vardi
 
Http Communication in Angular 2.0
Http Communication in Angular 2.0Http Communication in Angular 2.0
Http Communication in Angular 2.0Eyal Vardi
 
Angular 2.0 Dependency injection
Angular 2.0 Dependency injectionAngular 2.0 Dependency injection
Angular 2.0 Dependency injectionEyal Vardi
 
Angular 2.0 Routing and Navigation
Angular 2.0 Routing and NavigationAngular 2.0 Routing and Navigation
Angular 2.0 Routing and NavigationEyal Vardi
 
Angular 2.0 Pipes
Angular 2.0 PipesAngular 2.0 Pipes
Angular 2.0 PipesEyal Vardi
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 formsEyal Vardi
 
Iterators & Generators in ECMAScript 6.0
Iterators & Generators in ECMAScript 6.0Iterators & Generators in ECMAScript 6.0
Iterators & Generators in ECMAScript 6.0Eyal Vardi
 

Plus de Eyal Vardi (20)

Why magic
Why magicWhy magic
Why magic
 
Smart Contract
Smart ContractSmart Contract
Smart Contract
 
Rachel's grandmother's recipes
Rachel's grandmother's recipesRachel's grandmother's recipes
Rachel's grandmother's recipes
 
Performance Optimization In Angular 2
Performance Optimization In Angular 2Performance Optimization In Angular 2
Performance Optimization In Angular 2
 
Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)
 
Angular 2 NgModule
Angular 2 NgModuleAngular 2 NgModule
Angular 2 NgModule
 
Upgrading from Angular 1.x to Angular 2.x
Upgrading from Angular 1.x to Angular 2.xUpgrading from Angular 1.x to Angular 2.x
Upgrading from Angular 1.x to Angular 2.x
 
Angular 2 - Ahead of-time Compilation
Angular 2 - Ahead of-time CompilationAngular 2 - Ahead of-time Compilation
Angular 2 - Ahead of-time Compilation
 
Routing And Navigation
Routing And NavigationRouting And Navigation
Routing And Navigation
 
Angular 2 Architecture
Angular 2 ArchitectureAngular 2 Architecture
Angular 2 Architecture
 
Angular 1.x vs. Angular 2.x
Angular 1.x vs. Angular 2.xAngular 1.x vs. Angular 2.x
Angular 1.x vs. Angular 2.x
 
Angular 2.0 Views
Angular 2.0 ViewsAngular 2.0 Views
Angular 2.0 Views
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0
 
Template syntax in Angular 2.0
Template syntax in Angular 2.0Template syntax in Angular 2.0
Template syntax in Angular 2.0
 
Http Communication in Angular 2.0
Http Communication in Angular 2.0Http Communication in Angular 2.0
Http Communication in Angular 2.0
 
Angular 2.0 Dependency injection
Angular 2.0 Dependency injectionAngular 2.0 Dependency injection
Angular 2.0 Dependency injection
 
Angular 2.0 Routing and Navigation
Angular 2.0 Routing and NavigationAngular 2.0 Routing and Navigation
Angular 2.0 Routing and Navigation
 
Angular 2.0 Pipes
Angular 2.0 PipesAngular 2.0 Pipes
Angular 2.0 Pipes
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 forms
 
Iterators & Generators in ECMAScript 6.0
Iterators & Generators in ECMAScript 6.0Iterators & Generators in ECMAScript 6.0
Iterators & Generators in ECMAScript 6.0
 

AngularJS Compile Proccess

  • 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. 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. 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. 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. 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. ‫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‬‬ ‫סיכום:‬ ‫אני מקווה שהצלחתי לשפוך קצת אור על תהליך הקומפילציה של אנגולר ועל סדר הפעולות שמתרחש בזמן‬ ‫הקומפילציה. מידע נוסף אפשר למצוא בבלוג ובדף הפייסבוק.‬ ‫אשמח לשמוע פידבק ושאלות בנושא ‪‬‬