Как создать экземпляр службы динамически?

У меня есть служба Utils, которая очень тяжелая. Я хочу использовать некоторые функции, определенные в нем, для конкретного действия пользователя. Поскольку эта служба тяжелая, я хочу создать ее лениво (по действию пользователя).

Как мне этого добиться?

Сервис

module.service('Utils', function (dep1, dep2) {
   this.method1 = function () {
      // do something
   }
   // other methods
});

Контроллер

module.controller('AppCtrl', function ($scope) {
    // I don't want to inject Utils as a dependency.

    $scope.processUserAction = function () {
       // If the service is not instantiated 
       // instantiate it and trigger the methods defined in it. 
    }
});

Разметка

<div data-ng-controller="AppCtrl">
    <button data-ng-click="processUserAction()"> Click Me </button>
</div>

person Vinay K    schedule 28.03.2015    source источник
comment
что тяжелого в этом сервисе: большой ли JS-файл, поэтому вы хотите его лениво загружать? создание экземпляра службы занимает много времени, поэтому вы хотите отложить его? это большой объект в памяти, вы хотите сохранить память? в зависимости от ответа решение будет сильно отличаться. Но я не думаю, что вы что-то выиграете, не вводя его, потому что загрузка и создание экземпляра будут выполнены в любом случае, как только вы добавите свой сервис в свой модуль, и в любом случае это синглтон.   -  person Reto    schedule 28.03.2015
comment
Создание службы/фабрики происходит только тогда, когда мы внедряем их как зависимости. Тяжелыми средствами создание экземпляра службы занимает некоторое время. Чтобы ускорить загрузку страницы, я хочу лениво создавать экземпляр службы.   -  person Vinay K    schedule 28.03.2015
comment
скорректировал ответ, чтобы показать вам службу $injector, это решит вашу проблему   -  person Reto    schedule 28.03.2015


Ответы (1)


Вы можете использовать службу $injector для получения услуг в любом месте: https://docs.angularjs.org/api/auto/service/$injector. Вставьте $injector в свой контроллер, и всякий раз, когда вам понадобится служба, используйте:

У меня это сработало нормально, служба создается только при вызове $injector, ошибок не возникает.

 angular.module('yp.admin')

    .config(['$stateProvider', '$urlRouterProvider', 'accessLevels', '$translateWtiPartialLoaderProvider',
        function ($stateProvider, $urlRouterProvider, accessLevels, $translateWtiPartialLoaderProvider) {
            $stateProvider
                .state('admin.home', {
                    url: "/home",
                    access: accessLevels.admin,
                    views: {
                        content: {
                            templateUrl: 'admin/home/home.html',
                            controller: 'AdminHomeController'
                        }
                    }
                });
        }])
    .service('UtilsService', function() {
        console.log('utilsSerivce instantiated');
        return {
            call: function() {
                console.log('Util.call called');
            }
        };
    })

    .controller('AdminHomeController', ['$scope', '$rootScope', 'UserService', '$injector',
        function($scope, $rootScope, UserService, $injector) {
        $injector.get('UtilsService').call();
    }]);    

консоль выдает мне это:

stateChangeStart from:  to: admin.home
stateChangeSuccess from:  to: admin.home
utilsSerivce instantiated
Util.call called

Если вы хотите отложить загрузку JS, вам следует взглянуть на модуль ocLazyLoad: https://github.com/ocombe/ocLazyLoad. Он охватывает все виды вариантов использования ленивой загрузки, и ваш вариант подходит для этого.

person Reto    schedule 28.03.2015
comment
Если мы используем ocLazyLoad, нам нужно включить этот модуль в качестве зависимости. Я не хочу этого делать. Так же, как $controller для создания экземпляра контроллера, есть ли способ создать экземпляры сервисов/фабрик? - person Vinay K; 28.03.2015
comment
$inject вернет экземпляр службы/фабрики, если он уже создан. Если он не создан, он выдает ошибку. - person Vinay K; 28.03.2015
comment
используйте API $injector: вызовите $injector.has(). если false: вызовите $injector.instantiate() - person Reto; 28.03.2015
comment
instantiate(Type, [locals]) это сигнатура инстанцирующей функции. Тип здесь должен быть функцией. Он не может принимать serviceName. - person Vinay K; 28.03.2015
comment
Это должен быть провайдер, а не сервис или фабрика - person Pankaj Parkar; 28.03.2015
comment
Я попробовал пример в нашем коде. Добавил к ответу выше. Этот точный код работал без бросков и лениво запускал службу - person Reto; 28.03.2015
comment
@Reto, твое решение сработало для меня. Спасибо за это. Вместо включения $inject в качестве зависимости я попробовал angular.injector().get('Utils'). Это не сработало для меня. Есть идеи? - person Vinay K; 29.03.2015