Compilation process in Angular.js
06 Feb 2014
Entry point into compilation process is in doBootstrap function. To get rid of unneccessary context that code can be paraphrased in following way:
// root DOM element
var $rootElement = angular.element(window.document);
// setup builtin services
var $injector = angular.injector(['ng']);
// compiling
var $compile = $injector.get('$compile');
var compositeLinkFn = $compile($rootElement);
// linking
var $rootScope = $injector.get('$rootScope');
compositeLinkFn($rootScope);
function compile ($compileNodes, ...) {
// compiles DOM tree and make link function
var compositeLinkFn = compileNodes($compileNodes, ...);
return function publicLinkFn(scope, ...) {
// linking, this produces live view
compositeLinkFn(scope, ...);
};
}
Function compileNodes takes a list of DOM nodes -- [node1, node2, ..., nodeN].
It cycle [node1, node2, ..., nodeN] list, say current loop value is nodeK:
- Collects directives attached to nodeK by
collectDirectivesfunction. If there are any directives found they are applied by function
applyDirectivesToNodethat returnsnodeLinkFn-- a linking function for the nodeK. If no directives found thennodeLinkFnis set tonull. In a nutshell directive'scompilemethod is calledlinkFn = directive.compile($compileNode, ...);Returned
linkFnfunction will be called upon executingnodeLinkFn.compileNodesrecursively calls itself for childs of nodeK. This returnschildLinkFn-- a composite linking function. If there are no child thenchildLinkFnis set to null.Pushs link functions into array
linkFns.push(nodeLinkFn, childLinkFn)Remembers if where is anything apart from
nulllinkFnFound = linkFnFound || nodeLinkFn || childLinkFn`;
Finally after cycle ends compileNodes returns self explaining value
linkFnFound ? compositeLinkFn : null;
that is either closure compositeLinkFn or null. Key thing to remember is that compositeLinkFn contains linkFns array in it's environment: linkFns = [nodeLinkFn1, childLinkFn1, nodeLinkFn2, childLinkFn2, ..., nodeLinkFnN, childLinkFnN]
This nested structure of compositeLinkFn closures mimics DOM and is used in linking phase. For example, this DOM tree
is mimiced by the following 'tree' of link closures:
X[html] → [Yhtml, X[head, body]]
. X[head, body] → [Yhead, X[style], Ybody, X[input, p]]
. . X[style] → [Yhead, null]
. X[input, p] → [Yinput, null, Yp, X[#text]]
. . X[#text] → [Y#text, null]
where compositeLinkFn ≡ X
nodeLinkFn ≡ Y
→ ≡ "has in closure environment"
So $compile service applied to root DOM element returns compositeLinkFn[html]. Later one called with default scope turns DOM tree into live view equipped with two-way data bindings.
var compositeLinkFn = $compile($rootElement /* html root element */);
compositeLinkFn($rootScope);