loader.jsメモ

AngularJsのloader.jsを読んだ際のメモ
loader.suffix

setupModuleLoader(window)

loader.suffixでsetupModuleLoader(window);が実行される。
window.angularオブジェクトを作成する。
angular.module(name, requires, configFn)を生成する。
angular.module(name, requires, configFn)を返す。
下記の関数を多用している。

function ensure(obj, name, factory) {
    return obj[name] || (obj[name] = factory());
}


module(name, requires, configFn)

angular.moduleの実体
configFnはmodule.config()と同じ
requiresが存在するとmodulesのキャッシュをクリアする。
moduleInstance (ensure(modules, name, function() {)を返す。
moduleInstanceのインスタンスメソッドを以下のように登録している。

controller: invokeLater('$controllerProvider', 'register'),
value: invokeLater('$provide', 'value'),
constant: invokeLater('$provide', 'constant', 'unshift')


invokeLater(provider, method, insertMethod, queue)

moduleのインスタンスメソッドがinvokeQueueにロードするデータを登録する関数を返す。

myModule.value('appName', 'MyApp');
function invokeLater(provider, method, insertMethod, queue) {
    if (!queue) queue = invokeQueue;
    return function() {
        // 上の例ではargumentsは['appName', 'MyApp']
        queue[insertMethod || 'push']([provider, method, arguments]);
        return moduleInstance;
    };
}

invokeQueueはinjector.jsのloadModules(modulesToLoad)内のrunInvokeQueue(queue)で実行される。

function runInvokeQueue(queue) {
    var i, ii;
    for(i = 0, ii = queue.length; i < ii; i++) {
        var invokeArgs = queue[i],
            provider = providerInjector.get(invokeArgs[0]);

        // myModule.value('appName', 'MyApp');の場合は
        // value: invokeLater('$provide', 'value'),なので
        // $provide.value('appName', 'MyApp') 
        provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
    }
}

try {
    if (isString(module)) {
        moduleFn = angularModule(module);
        runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
        runInvokeQueue(moduleFn._invokeQueue);
        //var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
        runInvokeQueue(moduleFn._configBlocks);
    } else if (isFunction(module)) {