Почему использование $rootScope с функциями не рекомендуется?

В то время как я смотрю на FEQs Angularjs, я видел статью ниже:

$ rootScope существует, но его можно использовать для зла

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

Иногда есть фрагменты данных, которые вы хотите сделать глобальными для всего приложения. Для этого вы можете ввести $rootScope и установить значения в нем, как и в любой другой области видимости. Так как области видимости наследуются от корневой области видимости, эти значения будут доступны для выражений, прикрепленных к директивам, таким как ng-show точно так же, как значения в вашей локальной $scope.

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

И наоборот, не создавайте сервис, единственная цель которого - хранить и возвращать биты данных.

- AngularJS FAQ - $ rootScope существует, но его можно использовать для зла

Поэтому я сомневаюсь, почему $ rootScope не рекомендуется для функций как глобальной функции? Есть ли проблемы с производительностью?

Ответ 1

Я отвечал на это в прошлом, но хорошо, что ты задаешь эти вопросы.

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

Неизолированные области являются иерархическими, но большинство разработчиков должны использовать директивы, которые имеют изолированные области. Очень иерархическая природа области AngularJS является источником многих ошибок в угловых приложениях. Это проблема, которую я люблю называть областью кровотечения, когда свойство области магически изменяется где-то в дереве DOM, и вы не знаете почему.

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

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

Нет, это не правильно. AngularJS позволяет вам определять такие вещи, как константы, значения и сервисы. Это вещи, которые могут быть внедрены в маршруты, контроллеры и директивы. Это то, как вы делаете вещи доступными глобально для вашего приложения, и так, как вы делаете это, если хотите сделать свои контроллеры или директивы тестируемыми. Автор модульных тестов не знает, какие свойства должны быть в $ rootScope, от которых зависит директива или контроллер. Они должны предположить, что $ rootScope не мутировал для предоставления услуги или данных.

Конечно, глобальное состояние - отстой, и вы должны использовать $ rootScope экономно, как вы (надеемся) будете использовать с глобальными переменными на любом языке.

Проблема не в $ rootScope, а в том, что люди делают с ним. Многие приложения добавляют текущего пользователя, токены аутентификации и данные сеанса в rootScope. Это приводит к интенсивному использованию в шаблонах (показывает X, если пользователь вошел в систему, в противном случае показывает Y). Проблема в том, что HTML не передает иерархию области видимости. Поэтому, когда вы видите {{user.firstname + ' ' + user.lastname}} вы не знаете, откуда {{user.firstname + ' ' + user.lastname}} переменная user. Вторая проблема - дочерние области могут скрывать корневые свойства. Как и в предыдущем примере, если директива делает это scope.user = 'bla bla bla'. Он не заменил значение в rootScope. Это скрыло это. Теперь вы получаете некоторые странные неожиданные вещи в шаблонах, и вы не знаете, почему изменилась переменная user.

И наоборот, не создавайте сервис, единственная цель которого - хранить и возвращать биты данных.

Angular $cacheFactory и $templateCache являются примерами сервисов, которые существуют только для хранения данных. Я думаю, что автор пытался поощрять использование констант и значений в модулях Angular, но это не очень хорошее описание для этого.

Поэтому я сомневаюсь, почему $ rootScope не рекомендуется для функций как глобальной функции? Есть ли проблемы с производительностью?

$ RootScope - единственная область, доступная в angular.config(..). Это в течение этого времени, что область может быть изменена, если это единственный раз, когда вы можете это сделать. Например; Вам может потребоваться ввести ключ API или переменную Google Analytics до запуска приложения.

Функции в любой области - вообще плохая идея. Главным образом по той причине, что все в областях переваривается в выражениях на шаблонах. Функции палатки скрывают тяжелые операции. Невозможно определить, насколько тяжелым является шаблон, читая HTML-код при вызове функции. Я видел такие функции области видимости, как getHeight() где сама функция выполняла 3 уровня вложенных циклов. Эта функция должна вызываться каждый раз, когда angular переваривает наблюдателей, чтобы увидеть, изменилась ли она. Вы должны стараться, чтобы ваши шаблоны были максимально сухими.

Ответ 2

Глобальные переменные злоупотребляются

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

Нелокальность. Исходный код проще всего понять, когда объем его отдельных элементов ограничен. Глобальные переменные могут быть прочитаны или изменены любой частью программы, что затрудняет запоминание или рассуждение о каждом возможном использовании.

Контроль доступа или проверка ограничений. Глобальную переменную можно получить или установить любой частью программы, и любые правила ее использования могут быть легко сломаны или забыты. (Другими словами, get/set accessors, как правило, предпочтительнее прямого доступа к данным, и это тем более для глобальных данных.) По большому счету отсутствие контроля доступа значительно затрудняет достижение безопасности в ситуациях, когда вы, возможно, захотите запустить ненадежный код (например, работа с сторонними плагинами).

Неявная связь. Программа со многими глобальными переменными часто имеет плотные связи между некоторыми из этих переменных и связывание между переменными и функциями. Группирование связанных элементов в единые единицы обычно приводит к улучшению программ.

Concurrency выдает - если глобальные возможности могут быть доступны несколькими потоками выполнения, необходима синхронизация (и слишком часто игнорируется). При динамической компоновке модулей с глобалами составная система может быть небезопасной, даже если два независимых модуля, протестированных в десятках различных контекстов, были безопасными.

Загрязнение пространства имен. Глобальные имена доступны повсеместно. Вы можете неосознанно в конечном итоге использовать глобальное, когда вы думаете, что используете локальный (путем орфографии или забывания объявить локальный) или наоборот. Кроме того, если вам когда-либо понадобится связывать модули, имеющие одинаковые имена глобальных переменных, если вам повезет, вы получите ошибки связывания. Если вам не повезло, компоновщик будет просто рассматривать все виды использования с тем же именем, что и один и тот же объект.

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

Тестирование и конфайнмент - источник, который использует глобальные переменные, несколько сложнее проверить, потому что нельзя легко настроить "чистую" среду между прогонами. В более общем плане, источник, который использует глобальные сервисы любого типа (например, чтение и запись файлов или баз данных), которые явно не предоставлены этому источнику, трудно проверить по той же причине. Для коммуникационных систем способность тестировать системные инварианты может потребовать одновременного запуска более одной "копии" системы, что значительно затрудняется любым использованием общих служб, включая глобальную память, которые не предоставляются для совместного использования в рамках теста.

Источник: http://c2.com/cgi/wiki?GlobalVariablesAreBad

Обмен данными в Angular

Когда речь идет об обмене данными между контроллерами в Angular, вы должны использовать сервис. С помощью настраиваемого сервиса вы можете создать метод getter и setter. Вы вводите его в нужные вам контроллеры и можете использовать его в своем приложении.

Ответ 3

Не существует проблем с производительностью. Это фактически увеличило бы вашу производительность на долю времени, потому что вам не нужна зависимость - прикладывайте много услуг.

Но это большая проблема дизайна. Рассмотрите большое приложение с десятками и десятками просмотров, сложными компонентами и привязанными к ряду известных API (например, Twitter, Flickr, Facebook, OAuth,...).

Вы не будете разрабатывать это приложение самостоятельно. Будут возникать следующие проблемы:

Пространство имен

Вы работаете над API Facebook, кто-то работает над API Twitter. Вы оба думаете, что использование $rootScope для функций - хорошая идея, и оба записывают функцию $rootScope.login. Как вы разрешите это при выполнении git merge? Увы, вам нужно пространство имен, вам нужно разработать две службы myFacebookAPI, myTwitterAPI, которые затем могут реализовать тот же интерфейс для loggin in. (login(user,pw)). Обратите внимание, что это дает вам возможность абстрагировать фактическую социальную сеть, с которой вы имеете дело в контроллере, когда вы можете сделать что-то вроде:

$scope.callAction = function (action) {
var service;
    if ($scope.serviceSelected === 'fb') {
         service = myFacebookAPI;
    } else {
         service = myTwitterAPI;
    }
    service[action]();
};

Тестирование

При профессиональном развитии вы пишете тесты. Angular дает вам инструменты для автоматических тестов для служб и т.д., но вы не сможете проверить что-то, что вы назначаете $rootScope тем же удобным способом.

Также возникнут другие проблемы, но я думаю, этого должно быть достаточно, чтобы вы могли подумать об этом самостоятельно.