【问题标题】:How to instantiate a service dynamically?如何动态实例化服务?
【发布时间】:2015-03-28 15:38:45
【问题描述】:

我有一个很重的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>

【问题讨论】:

  • 该服务的“重”是什么:JS 文件很大,所以您想延迟加载它吗?服务实例化需要很多时间,所以你想延迟它吗?它是一个大的“内存”对象,你想节省内存吗?根据答案,解决方案将非常不同。但我认为“不注入”它不会获得任何好处,因为只要将服务添加到模块中,加载和实例化就会完成,而且无论如何它都是单例。
  • 服务/工厂的实例化只有在我们将它们作为依赖注入时才会发生。通过繁重的方式实例化服务需要一些时间。为了加快页面的加载速度,我想懒惰地实例化服务。
  • 调整答案以显示 $injector 服务,这将解决您的问题

标签: angularjs dependency-injection angular-services objectinstantiation


【解决方案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。它解决了各种延迟加载用例,你的听起来很适合它。

【讨论】:

  • 如果我们使用 ocLazyLoad,我们需要包含那个模块作为依赖。我不想那样做。就像 $controller 实例化一个控制器一样,有没有办法实例化服务/工厂?
  • $inject 将返回已经实例化的服务/工厂的实例。如果没有实例化,则会抛出错误。
  • 使用 $injector API:调用 $injector.has()。如果为假:调用 $injector.instantiate()
  • instantiate(Type, [locals]) 这是实例化函数的签名。这里的 Type 应该是一个函数。不能取 serviceName。
  • 应该是提供者而不是服务或工厂
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-26
  • 2014-01-26
相关资源
最近更新 更多