AngularJS 服务(Service)(超详细)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在 AngularJS 开发中,服务(Service) 是实现代码复用、模块化设计的关键工具。它如同应用程序的“心脏”,负责处理数据获取、状态管理、第三方库集成等核心逻辑,而控制器、指令等其他组件则专注于界面交互或视图渲染。对于编程初学者和中级开发者而言,理解服务的设计思想和使用方法,是掌握 AngularJS 核心架构的重要一步。


什么是 AngularJS 服务?

AngularJS 服务是可注入的 JavaScript 对象,用于封装可重用的业务逻辑或 HTTP 请求等操作。它们通过 AngularJS 的依赖注入(Dependency Injection)机制,被控制器、指令、过滤器或其他服务调用。

服务的核心特点

  1. 单例模式:每个服务在 AngularJS 应用中仅被实例化一次,确保数据和状态的全局一致性。
  2. 模块化:服务与视图逻辑分离,避免代码耦合。
  3. 可测试性:通过模拟(Mock)服务,可轻松进行单元测试。

比喻
可以将服务想象为一家公司的“后勤部门”。例如,前端控制器是“前台接待员”,负责与用户交互;而服务则是“仓库管理员”,负责存储、处理和分发数据,确保前台无需关心数据的具体来源或处理逻辑。


如何创建 AngularJS 服务?

AngularJS 提供了多种方式创建服务,最常见的包括 factoryservicevalueconstant。以下通过代码示例逐一讲解。

1. Factory(工厂模式)

factory 是最灵活的服务创建方式,返回一个包含方法或属性的对象。

示例:创建一个天气服务

// 定义模块
var app = angular.module('weatherApp', []);

// 创建 WeatherService 工厂
app.factory('WeatherService', function() {
  return {
    getWeather: function(city) {
      // 模拟异步请求
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve({ temperature: 25, condition: 'Sunny' });
        }, 1000);
      });
    }
  };
});

使用服务:在控制器中注入并调用

app.controller('WeatherCtrl', function($scope, WeatherService) {
  WeatherService.getWeather('Beijing')
    .then(function(response) {
      $scope.weather = response;
    });
});

2. Service(构造函数模式)

service 使用构造函数(通过 new 实例化)创建服务,适合需要复杂初始化逻辑或原型链继承的场景。

示例:创建一个计数器服务

app.service('CounterService', function() {
  this.count = 0;
  this.increment = function() {
    this.count++;
  };
});

使用服务

app.controller('CounterCtrl', function($scope, CounterService) {
  $scope.increment = function() {
    CounterService.increment();
    $scope.currentCount = CounterService.count;
  };
});

3. Value 和 Constant(简单值注入)

valueconstant 用于注入简单的数据对象或常量,区别在于 constant 可在配置阶段注入,而 value 仅在运行时可用。

示例:定义常量服务

app.constant('API_CONFIG', {
  baseUrl: 'https://api.example.com',
  timeout: 5000
});

app.value('UserPreferences', {
  theme: 'dark',
  language: 'en'
});

AngularJS 服务的应用场景

1. 数据共享与状态管理

服务是跨控制器共享数据的天然选择。例如,通过服务存储用户登录状态:

示例:用户认证服务

app.factory('Auth', function() {
  var user = null;

  return {
    setUser: function(u) {
      user = u;
    },
    getUser: function() {
      return user;
    }
  };
});

在两个控制器中共享用户数据:

// 登录控制器
app.controller('LoginCtrl', function(Auth) {
  Auth.setUser({ name: 'John', role: 'admin' });
});

// 仪表盘控制器
app.controller('DashboardCtrl', function($scope, Auth) {
  $scope.user = Auth.getUser();
});

2. HTTP 请求封装

通过服务封装 $http 请求,避免在控制器中重复编写网络逻辑。

示例:封装 API 调用

app.factory('DataService', function($http) {
  return {
    fetchUsers: function() {
      return $http.get('/api/users');
    },
    saveUser: function(user) {
      return $http.post('/api/users', user);
    }
  };
});

3. 第三方库集成

服务可封装第三方库(如 Moment.js、Lodash),使其在 AngularJS 中可测试且易于维护。

示例:集成 Moment.js

app.factory('DateService', function() {
  return {
    formatDateTime: function(date) {
      return moment(date).format('YYYY-MM-DD HH:mm');
    }
  };
});

服务的高级用法

1. 依赖注入(Dependency Injection)

服务之间可以互相依赖,通过参数名或 $inject 数组声明依赖关系。

示例:服务间依赖

app.factory('Logger', function() {
  return {
    log: function(msg) {
      console.log('Logger:', msg);
    }
  };
});

app.factory('UserService', ['Logger', function(Logger) {
  return {
    createUser: function(user) {
      Logger.log('Creating user:', user);
      // 执行创建逻辑
    }
  };
}]);

2. 服务的生命周期

服务默认是单例的,因此其初始化逻辑(如异步请求)仅执行一次。若需在每次调用时执行特定操作,可通过方法实现。

示例:延迟初始化

app.factory('LazyService', function() {
  var initialized = false;

  return {
    init: function() {
      if (!initialized) {
        // 执行初始化逻辑
        initialized = true;
      }
    },
    getData: function() {
      this.init();
      return 'Initialized data';
    }
  };
});

最佳实践与注意事项

1. 遵循单一职责原则

每个服务应专注于单一功能,例如:

  • AuthService 处理用户认证
  • ApiService 封装 API 请求
  • NotificationService 管理通知

2. 避免在服务中直接操作 DOM

服务应与视图逻辑分离,DOM 操作应由指令或控制器处理。

3. 使用依赖注入而非全局变量

避免通过全局变量共享数据,而是通过服务的依赖注入传递数据。

4. 测试服务的必要性

通过模拟(Mock)服务,可以独立测试业务逻辑。例如:

describe('WeatherService', function() {
  beforeEach(module('weatherApp'));

  it('should return weather data', inject(function(WeatherService) {
    var result = WeatherService.getWeather('London');
    expect(result).toBeDefined();
  }));
});

结论

AngularJS 服务是构建大型应用的基石,它通过模块化、可复用的设计,帮助开发者降低代码复杂度并提升可维护性。无论是处理数据共享、HTTP 请求,还是集成第三方库,服务都能以清晰的逻辑和优雅的结构解决问题。

对于初学者,建议从简单服务入手(如 factoryvalue),逐步过渡到复杂场景(如服务间依赖和异步操作)。对于中级开发者,可以深入探索服务与 AngularJS 生命周期的交互,以及如何通过服务优化应用性能。

掌握服务的设计模式,将使你在 AngularJS 开发中更加得心应手,为构建高效、可扩展的应用奠定坚实基础。

最新发布