Лучшая практика использования $rootscope в приложении Angularjs?

У нас есть большое приложение Angularjs 1.6, в котором $rootscope разбросан по всему приложению в более чем 200 местах в фильтрах, службах, маршрутах и ​​т. д., поэтому его необходимо реорганизовать, но я не уверен, как узнать, когда его удалить. Когда лучше всего использовать $rootscope в приложении?

Я прочитал все, от никогда до использования его для хранения переменных, которые, как я предполагал, были для обмена данными между контроллерами. С тех пор я читал, что вместо этого лучше использовать фабрики/сервисы для этого варианта использования, и я также читал, что одним из допустимых вариантов использования является использование $rootscope в качестве глобальной шины событий.

Я действительно не видел, чтобы это объяснялось в документах Angularjs.


person James Drinkard    schedule 11.02.2016    source источник


Ответы (3)


Из ng-book:

Когда Angular начнет работать и сгенерирует представление, он создаст привязку корневого элемента ng-app к $rootScope. Этот $rootScope является возможным родителем всех объектов $scope. Объект $rootScope — это ближайший к глобальному контексту объект в приложении Angular. Плохая идея — привязывать слишком много логики к этому глобальному контексту, точно так же, как не стоит загрязнять глобальную область видимости JavaScript.

Вы правы, вам определенно следует использовать Сервисы для обмена данными и логикой между вашими модулями.

Размещение большого количества логики в вашем $rootScope означает плохую ремонтопригодность и модульность вашего приложения, а также очень сложно тестировать проблемы.

Я настоятельно рекомендую вам ознакомиться с:

Я знаю, что может быть легко прикрепить все к $rootScope, но просто сложно работать над этим, вносить небольшие изменения, повторно использовать свой код для других приложений или модулей и тестировать свое приложение в целом.

ИЗМЕНИТЬ

Недавно мне пришлось получить некоторые элементы из API и поймать эти элементы, чтобы показать их в определенном представлении. Механизм получения элементов был в определенном Factory, а механизм форматирования и отображения элементов был в Controller.

Итак, мне пришлось генерировать событие в Factory, когда элементы были получены, и перехватывать это событие в Controller.

Путь $rootScope

//Factory
$rootScope.$broadcast('refreshItems', items);
//Controller
$scope.$on('refreshItems', doSomething());

Это явно сработало, но мне не очень нравилось использовать $rootScope, и я также заметил, что производительность этой задачи была довольно жалкой.

Затем я попытался попробовать Postal.js:

Postal.js — это шина сообщений в памяти, очень слабо вдохновленная AMQP, написанная на JavaScript. Postal.js запускается в браузере или на сервере с помощью node.js. Он берет знакомую парадигму «событийного стиля» (известную большинству разработчиков JavaScript) и расширяет ее, предоставляя реализации «брокера» и подписчика, которые являются более сложными, чем те, которые вы обычно найдете в простой генерации/агрегации событий.

Я попытался использовать Postal.js для таких нужд и обнаружил, что это действительно быстрее, чем использование $rootScope для этой цели.

//Factory
$scope.$bus.publish({
                  channel : 'reloadItems',
                  topic   : 'reloadItems'
                  data    : items
);

//Controller
$scope.$bus.subscribe({
  channel  : 'reloadItems',
  topic    : 'reloadItems',
  callback : function () {
    resetAndLoadItems();
  }
});

Надеюсь, я был полезен.

person AndreaM16    schedule 11.02.2016
comment
Проблема в том, что они используются во всем приложении, для всего, и нам нужно реорганизовать их, поэтому обмен данными — это только одна проблема. - person James Drinkard; 11.02.2016
comment
Я понимаю, что вы имеете в виду. Что ж, я думаю, что если вы действительно вынуждены реорганизовать приложение, вам нужно будет написать отдельные модули для инкапсуляции различной логики. Это займет приличное количество времени! Если вы ищете лучшие практики для инкапсуляции логики в разные модули, просто взгляните на Документацию по модулям. . Я также настоятельно рекомендую вам попробовать реализовать небольшую демонстрацию, чтобы понять, как работать с некоторыми отдельными модулями, с их соответствующими контроллерами, службами и областями, и, в конце концов, начать рефакторинг. - person AndreaM16; 11.02.2016
comment
Если у меня есть служба, которая часто используется во всем моем приложении, и мне нужно подключиться ко многим контроллерам, есть ли лучший способ, чем внедрить ее во все остальные контроллеры? сделать его доступным через $ rootScope? Немного нового в Advanced Angular Concepts. - person Divij Sehgal; 10.07.2017

Из документов Angluar: Каждое приложение имеет единую корневую область. Все остальные области являются дочерними областями корневой области. Области обеспечивают разделение между моделью и представлением с помощью механизма отслеживания изменений модели.

Конечно, это будет зависеть от мнения и стиля. Я склонен следовать стилю, очень близкому к Руководству по стилю Angular Джона Папы.

В соответствии с этими двумя и следуя стратегии хорошего разделения задач, моя архитектура содержит фабричные модели, которые являются общими для всего приложения. Мои контроллеры, в свою очередь, привязаны к службам, которые содержат общие данные.

Использование $rootScope в качестве глобальной шины событий — это именно то, как его использует Angular. Должны ли вы последовать за ним и сделать то же самое? Я не понимаю, почему бы и нет. Но если да, убедитесь, что цель четко определена, и, возможно, даже используйте свой собственный сервис для регистрации событий в глобальной шине событий. Таким образом, вы отделяете свое приложение от Angular, и если вы когда-нибудь решите изменить структуру, в которой живет ваша глобальная шина событий, вы можете изменить ее в одном месте.

Вот что я предлагаю:

Глобальная шина событий

// Angular specific: add service to module
angular.module('app').factory('globalEventBus', GlobalEventBus);

// Angular specific: inject dependencies
GlobalEventBus.$inject(['$rootScope']);

// Non framework specific. 
// param: fameworkEventBus will be $rootScope once injected 
function GlobalEventBus(fameworkEventBus) {

  var globalEventBus = this;

  globalEventBus.registerEvent(params...){
    fameworkEventBus.
  }

  return globalEventBus;
}

Глобальные модели данных

Мои модели данных умны и, как правило, содержат функции, которые предоставляют информацию о себе или извлекают/возвращают определенные данные.

// Angular specific: add service to module
angular.module('app').factory('dataModel', DataModel);

function DataModel() {

  var dataModel= this;

  dataModel.myData = {};

  dataModel.GetSpecificData = funtion(param){
    return ...
  }

  return dataModel;
}

Контроллер

// Angular specific
angular.module('app').controller('MyController', MyController);

// Angular specific: inject dependencies to controller
MyController.$inject = ['dataModel'];

// By convention I use the same parameter name as the service.
// It helps me see quickly if my order of injection is correct
function MyController(dataModel) {

  var myController = this;

  // Bind to the service itself, and NOT to the service data property
  myController.myData = dataModel;

  myController.doStuff = function(){
  }
}

Вот забавный пост о привязке к службам, а не к свойствам службы.

В общем, вы должны быть судьей того, что лучше всего подходит для вас. Хорошая системная архитектура и хороший стиль сэкономили мне бесчисленное количество часов решения проблем, которых можно было избежать.

person Wilmer SH    schedule 11.02.2016
comment
Не могли бы вы пояснить, как используется FameworkEventBus? - person Augustas; 18.10.2016

После дополнительной работы с Angular и дальнейшего чтения я нашел это основное практическое правило использования $rootscope, которое я хотел добавить к другим ответам:

Добавляйте только статические или постоянные свойства. Все остальное, что представляет изменяющееся состояние или изменяемое значение, должно иметь соответствующую директиву или контроллер для обработки.

person James Drinkard    schedule 31.03.2016