Сервисы в Ember.js — это особая категория объектов, предназначенных для централизованного управления состоянием и логикой, которые могут быть использованы в различных частях приложения. Они служат для инкапсуляции бизнес-логики, работы с API, управления состоянием приложения и других аспектов, которые не зависят от жизненного цикла компонента или маршрута.
Для создания сервиса в Ember.js используется командой:
ember generate service имя_сервиса
Эта команда создаёт файл сервиса в директории
app/services. Структура сервиса обычно включает только
основные методы и свойства, которые необходимы для реализации нужной
логики. Сервисы в Ember наследуют от базового класса
Service.
Пример сервиса:
// app/services/authentication.js
import Service from '@ember/service';
export default class AuthenticationService extends Service {
isAuthenticated = false;
login() {
this.isAuthenticated = true;
}
logout() {
this.isAuthenticated = false;
}
}
В этом примере сервис authentication управляет
состоянием аутентификации пользователя, предоставляя методы для входа и
выхода.
Сервисы инжектируются в компоненты, маршруты и контроллеры через
систему зависимостей, предоставляемую Ember. Это делается с помощью
декоратора @service.
Пример использования сервиса в компоненте:
// app/components/login-form.js
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
export default class LoginFormComponent extends Component {
@service authentication;
get isAuthenticated() {
return this.authentication.isAuthenticated;
}
login() {
this.authentication.login();
}
logout() {
this.authentication.logout();
}
}
В этом примере сервис authentication инжектируется в
компонент login-form и используется для управления
состоянием аутентификации.
Сервисы в Ember.js работают как фабрики. Это означает, что экземпляр сервиса создается один раз в рамках приложения и используется повторно во всех частях приложения, где он инжектирован.
Если необходимо создать несколько экземпляров сервиса с различными
состояниями, можно использовать опцию “сервисов фабричного типа”. Для
этого вместо стандартного Service используется кастомная
реализация или библиотека, позволяющая создавать такие экземпляры.
Однако, в стандартных случаях Ember создает только один экземпляр
сервиса на всё приложение.
Сервисы могут быть полезны не только в компонентах и контроллерах, но и в маршрутах. Чтобы использовать сервис в маршруте, его нужно инжектировать аналогичным способом:
// app/routes/application.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ApplicationRoute extends Route {
@service authentication;
beforeModel() {
if (!this.authentication.isAuthenticated) {
this.transitionTo('login');
}
}
}
В этом примере маршрут application проверяет,
авторизован ли пользователь, с помощью сервиса
authentication, и, если нет, перенаправляет его на страницу
входа.
Сервисы часто используются для хранения глобального состояния, которое должно быть доступно на протяжении всей жизни приложения. Например, сервис может отслеживать данные о текущем пользователе, настройки приложения или состояние глобального уведомления.
Пример сервиса, управляющего состоянием темы оформления:
// app/services/theme.js
import Service from '@ember/service';
export default class ThemeService extends Service {
currentTheme = 'light';
toggleTheme() {
this.currentTheme = this.currentTheme === 'light' ? 'dark' : 'light';
}
}
Этот сервис позволяет переключать темы в приложении. Состояние темы будет доступно во всех компонентах и маршрутах, которые инжектируют этот сервис.
Сервисы могут содержать асинхронную логику, такую как запросы к API. Например, сервис может обрабатывать HTTP-запросы, получать данные с сервера и предоставлять эти данные компонентам и маршрутам.
Пример асинхронного сервиса для работы с API:
// app/services/api.js
import Service from '@ember/service';
import fetch from 'fetch';
export default class ApiService extends Service {
async fetchData(url) {
const response = await fetch(url);
const data = await response.json();
return data;
}
}
Этот сервис предоставляет метод fetchData, который
делает асинхронный запрос к API и возвращает данные. Он может быть
использован в любом компоненте или маршруте, который нуждается в этих
данных.
Сервисы в Ember могут быть также использованы в тестах. Для того
чтобы инжектировать сервис в тест, используется метод
setupTest из Ember Test Framework. Сервисы обычно
инжектируются через this.owner.lookup или через
предоставление их в контексте теста.
Пример теста с использованием сервиса:
// tests/unit/services/authentication-test.js
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Service | authentication', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
let service = this.owner.lookup('service:authentication');
assert.ok(service);
});
test('login and logout', function(assert) {
let service = this.owner.lookup('service:authentication');
service.login();
assert.ok(service.isAuthenticated);
service.logout();
assert.notOk(service.isAuthenticated);
});
});
Тест проверяет, что сервис аутентификации работает корректно, включая
методы login и logout.
Сервисы в Ember.js предоставляют мощный инструмент для централизованного управления состоянием и бизнес-логикой приложения. Они позволяют инкапсулировать логику, которая должна быть доступна в различных частях приложения, и обеспечивают долгосрочную доступность состояния на протяжении всего времени работы приложения. Инжекция сервисов в компоненты, маршруты и контроллеры упрощает взаимодействие между различными частями приложения и способствует улучшению структуры кода.