Created
July 16, 2014 21:26
-
-
Save toddmotto/2455226d057f76488f39 to your computer and use it in GitHub Desktop.
Angular's annotation mapping process and performance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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