Почему использование $rootScope с функциями не рекомендуется?
В то время как я смотрю на FEQs Angularjs, я видел статью ниже:
$rootScope существует, но его можно использовать для зла
Области в Angular образуют иерархию, прототипно наследуя от корневой области видимости в верхней части дерева. Обычно это можно игнорировать, поскольку большинство представлений имеют собственный контроллер и, следовательно, область видимости.
Иногда есть фрагменты данных, которые вы хотите сделать глобальными для всего приложения. Для этого вы можете ввести
$rootScope
и установить значения на него, как и любой другой объем. Так как области видимости наследуются от корневой области видимости, эти значения будут доступны для выражений, связанных с такими директивами, какng-show
так же, как значения на вашем местном$scope
,Конечно, глобальное состояние отстой, и вы должны использовать
$rootScope
экономно, как вы (надеюсь) использовать с глобальными переменными на любом языке. В частности, не используйте его для кода, только для данных. Если вы склонны поставить функцию на$rootScope
почти всегда лучше поместить его в службу, которую можно внедрить там, где это необходимо, и ее легче протестировать.И наоборот, не создавайте сервис, единственная цель которого - хранить и возвращать биты данных.
- AngularJS FAQ - $rootScope существует, но его можно использовать для зла
Поэтому я сомневаюсь, почему $rootScope не рекомендуется для функций как глобальной функции? Есть ли проблемы с производительностью?
3 ответа
Я отвечал на это в прошлом, но хорошо, что ты задаешь эти вопросы.
$rootScope существует, но он может использоваться для злых областей в угловой форме иерархии, прототипно наследуя от корневой области видимости в верхней части дерева. Обычно это можно игнорировать, поскольку большинство представлений имеют собственный контроллер и, следовательно, область видимости.
Неизолированные области являются иерархическими, но большинство разработчиков должны использовать директивы, которые имеют изолированные области. Очень иерархическая природа области действия AngularJS является источником многих ошибок в угловых приложениях. Это проблема, которую мне нравится называть областью кровотечения, когда свойство области магически изменяется где-то в дереве DOM, и вы не знаете почему.
Поведение Angular по умолчанию относится к собственным областям, и это заставляет один контроллер заманчиво обновлять что-то, управляемое другим контроллером, и так далее, и так далее. Вот как создаются спагетти-связи между исходным кодом. Это очень усложняет поддержку этого кода.
Иногда есть фрагменты данных, которые вы хотите сделать глобальными для всего приложения. Для этого вы можете ввести $rootScope и установить значения в нем, как и в любой другой области видимости.
Нет, это не правильно. AngularJS позволяет вам определять такие вещи, как константы, значения и сервисы. Это вещи, которые могут быть внедрены в маршруты, контроллеры и директивы. Это то, как вы делаете вещи доступными глобально для вашего приложения, и так, как вы делаете это, если хотите сделать свои контроллеры или директивы тестируемыми. Автор модульных тестов не знает, какие свойства должны быть в $rootScope, от которых зависит директива или контроллер. Они должны предположить, что $rootScope не мутировал для предоставления услуги или данных.
Конечно, глобальное состояние - отстой, и вы должны использовать $rootScope экономно, как вы (надеюсь) использовали бы с глобальными переменными на любом языке.
Проблема не в $rootScope, а в том, что люди делают с ним. Многие приложения добавляют текущего пользователя, токены аутентификации и данные сеанса в rootScope. Это приводит к интенсивному использованию в шаблонах (показывает X, если пользователь вошел в систему, в противном случае отображается Y). Проблема в том, что HTML не связывает иерархию области видимости. Итак, когда вы видите {{user.firstname + ' ' + user.lastname}}
Вы понятия не имеете, где переменная user
пришли из. Вторая проблема - дочерние области могут скрывать корневые свойства. Как в предыдущем примере, если директива делает это scope.user = 'bla bla bla'
, Он не заменил значение в rootScope. Это скрыто. Теперь вы получаете некоторые странные неожиданные вещи в шаблонах, и вы не знаете, почему переменная user
изменился
И наоборот, не создавайте сервис, единственная цель которого - хранить и возвращать биты данных.
Радиально-х $cacheFactory
а также $templateCache
Примеры сервисов, которые существуют только для хранения данных. Я думаю, что автор пытался поощрять использование констант и значений в модулях Angular, но это не очень хорошее описание для этого.
Поэтому я сомневаюсь, почему $rootScope не рекомендуется для функций как глобальной функции? Есть ли проблемы с производительностью?
$ RootScope - единственная область, доступная во время angular.config(..)
, В это время можно изменить область действия, если это единственный раз, когда вы можете это сделать. Например; Вам может потребоваться ввести ключ API или переменную Google Analytics до запуска приложения.
Функции в любой области - вообще плохая идея. Главным образом по той причине, что все в областях переваривается в выражениях на шаблонах. Функции палатки скрывают тяжелые операции. Невозможно сказать, насколько тяжелый шаблон, читая HTML, когда он вызывает функцию. Я видел функции области видимости, такие как getHeight()
где сама функция выполнила 3 уровня вложенных циклов. Эта функция должна вызываться каждый раз, когда angular переваривает наблюдателей, чтобы увидеть, изменилась ли она. Вы должны стараться, чтобы ваши шаблоны были максимально сухими.
Бесстыдная самореклама здесь:
http://www.thinkingmedia.ca/2015/01/learn-how-to-use-scopes-properly-in-angularjs/
Глобальные переменные злоупотребляют
$rootScope
является в значительной степени глобальной переменной и имеет свое место, но определенно злоупотребляет большинством людей, которые ее используют. Это причины, по которым глобалы вообще не должны использоваться.
Нелокальность. Исходный код легче всего понять, когда область его отдельных элементов ограничена. Глобальные переменные могут быть прочитаны или изменены любой частью программы, что затрудняет их запоминание или рассуждение о каждом возможном использовании.
Отсутствие контроля доступа или проверки ограничений - глобальная переменная может быть получена или установлена любой частью программы, и любые правила, касающиеся ее использования, могут быть легко нарушены или забыты. (Другими словами, средства доступа get/set обычно предпочтительнее прямого доступа к данным, и это в большей степени относится к глобальным данным.) В силу этого отсутствие контроля доступа значительно препятствует достижению безопасности в ситуациях, когда вы можете захотеть запустить ненадежный код (например, работа со сторонними плагинами).
Неявная связь - Программа со многими глобальными переменными часто имеет тесную связь между некоторыми из этих переменных и связь между переменными и функциями. Группировка связанных элементов в единые блоки обычно приводит к улучшению программ.
Проблемы параллелизма - если глобальные потоки могут быть доступны нескольким потокам выполнения, синхронизация необходима (и слишком часто игнорируется). При динамическом связывании модулей с глобальными переменными составная система может быть поточно-ориентированной, даже если два независимых модуля, протестированных в десятках различных контекстов, были безопасными.
Загрязнение пространства имен - Глобальные имена доступны везде. Вы можете неосознанно использовать глобальную переменную, когда считаете, что используете локальную (ошибкой или забыли объявить локальную) или наоборот. Кроме того, если вам когда-либо придется связывать вместе модули с одинаковыми именами глобальных переменных, если вам повезет, вы получите ошибки связывания. Если вам не повезло, компоновщик просто обработает все случаи использования одного и того же имени с одним и тем же объектом.
Проблемы с выделением памяти. В некоторых средах существуют схемы выделения памяти, которые усложняют распределение глобалов. Это особенно верно в языках, где "конструкторы" имеют побочные эффекты, отличные от распределения (потому что в этом случае вы можете выразить небезопасные ситуации, когда два глобальных элемента взаимно зависят друг от друга). Кроме того, при динамическом связывании модулей может быть неясно, имеют ли разные библиотеки свои собственные экземпляры глобалов или глобальные глобальные ресурсы являются общими.
Тестирование и ограничение - источник, использующий глобальные переменные, несколько сложнее протестировать, поскольку нельзя легко установить "чистую" среду между запусками. В более общем смысле, источник, который использует глобальные сервисы любого рода (например, чтение и запись файлов или баз данных), которые явно не предоставлены этому источнику, трудно проверить по той же причине. Для взаимодействующих систем возможность тестирования системных инвариантов может потребовать одновременного запуска более одной "копии" системы, что сильно затрудняется любым использованием общих служб, включая глобальную память, которые не предоставляются для совместного использования в рамках теста.,
Источник: http://c2.com/cgi/wiki?GlobalVariablesAreBad
Обмен данными в Angular
Когда дело доходит до обмена данными между контроллерами в Angular, вы должны использовать сервис. С помощью пользовательского сервиса вы можете создать метод получения и получения. Вы вводите его в нужные вам контроллеры и можете использовать его в своем приложении.
Там нет никаких проблем с производительностью. Это на самом деле повысит вашу производительность за короткий промежуток времени, потому что вам не нужно вводить зависимости во многих службах.
Но это большая проблема дизайна. Рассмотрим большое приложение с десятками и десятками представлений, сложными компонентами и связанными с рядом известных API (например, Twitter, Flickr, Facebook, OAuth, ...).
Вы не будете разрабатывать это приложение в одиночку. Возникнут следующие проблемы:
Пространства имен
Вы работаете над API Facebook, кто-то еще работает над API Twitter. Вы оба думаете, что используя $rootScope
для функций это хорошая идея, и оба пишут $rootScope.login
функция. Как бы вы решили это при выполнении git merge
? Вам нужно пространство имен, увы, вам нужно разработать два сервиса myFacebookAPI
, myTwitterAPI
который затем может реализовать тот же интерфейс для входа в систему. (login(user,pw)
). Обратите внимание, что это дает вам возможность абстрагироваться от реальной социальной сети, с которой вы работаете, в контроллере, когда вы можете сделать что-то вроде:
$scope.callAction = function (action) {
var service;
if ($scope.serviceSelected === 'fb') {
service = myFacebookAPI;
} else {
service = myTwitterAPI;
}
service[action]();
};
тестирование
При профессиональном развитии вы пишете тесты. Angular предоставляет вам инструменты для автоматического тестирования сервисов и т. Д., Но вы не сможете протестировать то, что вам назначено $rootScope
таким же удобным способом.
Будут возникать и другие проблемы, но я думаю, что этого будет достаточно, чтобы вы думали об этом самостоятельно.