Skip to content

Instantly share code, notes, and snippets.

@toddmotto
Created July 16, 2014 21:26
Angular's annotation mapping process and performance
/**
* Read the post for full details, hope these comments are helpful!
* http://toddmotto.com/angular-js-dependency-injection-annotation-process
*/
function annotate(fn, strictDi, name) {
var $inject,
fnText,
argDecl,
last;
// if the function passed in is a function, let's roll with it...
// ...there are two things that can happen inside here, either we're using $inject or
// we aren't using $inject, which means we'll manually need to get the dependencies
// from the arguments
if (typeof fn === 'function') {
// !($inject = fn.$inject) checks for the presence
// of fn.$inject and assigns it to the $inject variable, if this is true
// there is no further action needed, and $inject is returned
// which is a very fast operation
if (!($inject = fn.$inject)) {
// if fn.$inject doesn't exist, it's bad news and we're going to need to
// do some manual work reading the dependencies from the arguments, so they
// need to be spelled correctly against the proper names or they'll be an
// unknown provider
$inject = [];
if (fn.length) {
if (strictDi) {
if (!isString(name) || !name) {
name = fn.name || anonFn(fn);
}
throw $injectorMinErr('strictdi',
'{0} is not using explicit annotation and cannot be invoked in strict mode', name);
}
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
arg.replace(FN_ARG, function(all, underscore, name){
$inject.push(name);
});
});
}
// here after we're done, it completes what we wanted before this
// operation, the fn.$inject, so it just assigns $inject to the function
// and $inject gets returned below
fn.$inject = $inject;
}
} else if (isArray(fn)) {
// if the function isn't a function, but is an Array containing a function
// we need to remove it from the Array and send the leftover portion of the
// Array back as $inject
// calculate the Array length
last = fn.length - 1;
assertArgFn(fn[last], 'fn');
// use slice which returns the portion of the Array minus the final item
// this is a lot heavier of an operation than using $inject!
$inject = fn.slice(0, last);
} else {
assertArgFn(fn, 'fn', true);
}
// returns $inject from one of the methods above!
return $inject;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment