Problema com inicialização manual e substituição de serviços angulares na configuração

Estou tentando fazer com que meu aplicativo angular funcione no modo ao vivo e no modo de protótipo apenas substituindo os serviços. Como parte disso, quando o modo de protótipo está ativado na configuração, interrompo o processo de inicialização, carrego arquivos de serviços simulados (js) e continuo a inicialização.

Aqui está uma lista simplificada de código fonte para preparar odemonstração: -

App.js

Apenas meu aplicativo, que para simulação chama o serviço e exibe o resultado. ExigiaStubApp bem como quem fornecer isso vai usar para substituir os serviços

var app = angular.module('app', ['StubsApp'])

.run([ '$rootScope', 'DataService', function($scope, DataService){
   DataService.getData().then(function(data){
    $scope.name = data;
  });
}]);

DataService.js

Apenas um serviço simples registrado com o aplicativo.

function DataService($q){
  this.getData = function(){
       return $q.when('I am Real!!');
  }
}
DataService.$inject = ['$q'];
angular.module('app').service('DataService',DataService);

Driver.js

Apenas o registro de configuração que irá configurar a zombaria.

angular.module('app').config(['$provide', 'stubServiceProvider', 'AppConfig', function($provide, stubProvider, AppConfig){
    if(AppConfig.StubEnabled){
       stubProvider.loadStubsInModule('plunker');
    }
}]);

StubProvider.js

Isso expõe uma interface semelhante aangular.module para registrar serviços de stub. também procurastubs.json que tem a lista de serviços simulados que são carregados interrompendo a inicialização. Também expõe um fornecimento que um aplicativo pode usar para configurar a sobrecarga de serviços existentes com os stubs.json

var Stubs = {},
    modules = [];
function module(moduleName) {
    return {
        mock: function (func) {
            modules.push(func);
        }, get: function () {
            return modules;
        }
    };
}
Stubs.module = module;

loadStubs();

function loadStubs() {
    window.name = "NG_DEFER_BOOTSTRAP!";
    var injector = angular.injector(['ng']);
    var $q = injector.get('$q');
    var $http = injector.get('$http');
    var scripts = [];

    $http.get('stubs.json').then(function (result) {
        scripts = result.data.map(function (src) {
            var script = document.createElement('script');
            script.src = src;
            script.async = true;
            document.head.appendChild(script);

            var defered = $q.defer();

            script.onload = function () {
                defered.resolve();
            };
            return defered.promise;
        });

        $q.all(scripts).finally(function () {
            angular.element().ready(function () {
                angular.resumeBootstrap();
            });
        });
    });
}

//This is the provider which actually will do the overriding
angular.module('StubsApp', []).provider('stubService', function ($provide) {
    ...... //Code in plunker
});

DataService Mock.js

Este é apenas um mock que realmente usa a interface Stubs para registrar o mockStubs.module('app').mock(MockService) e o ctor tem uma propriedadestubFor="serviceName" que diz qual serviço isso realmente zomba

function MockService($q, $log){
this.getData = function(){
       return $q.when('I am Mock!!');
  }
}
MockService.$inject = ['$q', '$log'];

MockService.stubFor="DataService";

Stubs.module('app').mock(MockService);

stubs.json

Apenas um arquivo json simples que especifica as zombarias

["DataServiceMock.js"]

index.html

<script src="app.js"></script>
<script src="DataService.js"></script>
<script src="Driver.js"></script>
<script src="stubprovider.js"></script>

Isso funciona bem. Agora, a questão é que quando eu mudoDriver.js Arquivoantes do registro do serviço isto éDataService.js não vai mais zombar. Parte específica do código que executa a substituição no "StubProvider.js" é

   Stubs.module(moduleName).get().forEach(function (mod) {
        var serviceName = mod.stubFor;
        var ctor = mod;
        if (serviceName) {
            $provide.service(serviceName, ctor);
        }
    });

Aqui está umDemo Plnkr Se você comentar a linha noDriver.js você pode ver que a saída será do serviço real, caso contrário, será do serviço simulado. E para replicar o problema no modo index.htmlDriver.js antesDataService.js ele não substituirá o DataService pelo MockDataservice.

Por que a ordem do registro da configuração é importante, a fase de configuração deve ser executada antes que a instanciação do serviço seja corrigida?

Existe um padrão melhor para garantir que todos os scripts sejam carregados antes de retomar o processo de autoinicialização em vez de usar o padrão adiado.

questionAnswers(1)

yourAnswerToTheQuestion