$ rootScope. $ широковещание против $ scope. $ emit

307

Теперь, когда разница в производительности между $broadcast и $emit была устранена, есть ли какая-либо причина предпочесть от $scope.$emit до $rootScope.$broadcast?

Они разные, да.

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

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

Я что-то пропустил?

EDIT:

Чтобы пояснить ответ в ответ, направление отправки не является проблемой, за которой я нуждаюсь. $scope.$emit отправляет событие вверх, а $scope.$broadcast - вниз. Но почему бы не всегда использовать $rootScope.$broadcast для охвата всех предполагаемых слушателей?

Теги:
angularjs-scope

6 ответов

1081
Лучший ответ

tl; dr (это tl; dr от @sp00m ниже)

$emit отправляет событие вверх... $broadcast отправляет событие вниз

Подробное объяснение

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

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

$scope.$emit - это когда вы хотите, чтобы $scope и все его родители и $rootScope услышали это событие. Это ребенок, скулящий к родителям дома (но не в продуктовом магазине, где могут слышать другие дети).

$scope.$broadcast для самого $scope и его дочерних элементов. Это ребенок, шепчущий своим чучелам, чтобы их родители не слышали.

  • 0
    Спасибо за ответ. В центре моего вопроса было то, почему использовать иерархию контекста как способ ограничения аудитории? Аудитория уже «ограничена» в том смысле, что контролеры выбирают, что слушать. Я уточнил в этом вопросе, что прекрасно понимаю различие между $emit и $broadcast , но не понимаю необходимости ограничений на основе иерархии областей действия.
  • 3
    @NewDev Причина в том, что часто у вас есть повторение областей на странице. Если у вас есть две или более областей, представляющих разные экземпляры данных - например, список записей о пациентах на странице, каждая со своей областью действия - тогда она не будет работать для передачи из корня события, предназначенного только для одного из них. прицелы. Избегание трансляций $rootScope где это возможно, позволяет лучше использовать повторно.
Показать ещё 22 комментария
95

Они не выполняют одно и то же задание: $emit отправляет событие вверх по иерархии областей, а $broadcast отправляет событие вниз во все дочерние области.

  • 2
    Да, я отметил это в вопросе (возможно, я мог бы дать понять о направлении отправки). Но я также отметил, что это довольно произвольное ограничение. Если я могу связаться со своим «слушателем», почему я не могу всегда делать это вниз от $rootScope ?
  • 0
    Потому что $ emit не повлияет на дочерние или родственные области видимости. Они просто сопоставляются с типами распространения событий javascript - захват и пузыри. $ broadcast используется для захвата, а $ emit используется для всплытия. Есть теперь, казалось бы, древняя статья о моде, которая хорошо объясняет разницу: quirksmode.org/js/events_order.html
63

Я сделал следующий рисунок из следующей ссылки: https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

Изображение 3656

Как вы можете видеть, $rootScope.$broadcast показывает гораздо больше слушателей, чем $scope.$emit.

Кроме того, эффект $scope.$emit может быть отменен, тогда как $rootScope.$broadcast не может.

  • 24
    Я вижу много стрел.
  • 4
    @MichalStefanow Я фанат визуальных ответов :)
Показать ещё 1 комментарий
4

Изображение 3657

$scope. $emit: этот метод отправляет событие в направлении вверх (от дочернего к родительскому)

Изображение 3658 $ scope. $broadcast: метод отправляет событие в направлении вниз (от родителя к дочернему) ко всем дочерним контроллерам.

Изображение 3659 $ scope. $on: Методические регистры для прослушивания некоторого события. Все контроллеры, которые слушают это событие, получают уведомление о трансляции или испускании на основе где они соответствуют иерархии дочерних и родительских.

Событие $emit может быть отменено любым из $scope, который слушает событие.

$on предоставляет метод stopPropagation. Вызывая этот метод, событие может быть остановлено от дальнейшего распространения.

Plunker: https://embed.plnkr.co/0Pdrrtj3GEnMp2UpILp4/

В случае областей брака (области, которые не находятся в иерархии прямого родительского и дочернего), $emit и $broadcast не будут сообщаться с областями брака.

Изображение 3660

Для получения дополнительной информации см. http://yogeshtutorials.blogspot.in/2015/12/event-based-communication-between-angularjs-controllers.html

  • 0
    Ссылка на решение приветствуется, но, пожалуйста, убедитесь, что ваш ответ полезен без нее: добавьте контекст вокруг ссылки, чтобы ваши коллеги-пользователи имели представление о том, что это такое и почему, а затем процитируйте наиболее релевантную часть страницы, которую вы ' Ссылка в случае, если целевая страница недоступна. Ответы, которые немного больше, чем ссылка, могут быть удалены.
  • 0
    Цель состояла в том, чтобы предоставить работающему поршню, однако я добавил здесь соответствующее описание.
3

@Эдди дал прекрасный ответ на заданный вопрос. Но я хотел бы обратить внимание на использование более эффективного подхода к Pub/Sub.

Как этот говорит,

Подход $broadcast/$on не очень эффективен, поскольку он транслирует все области (либо в одном направлении, либо в обоих направлениях иерархии Scope). В то время как подход Pub/Sub намного более прямой. Только подписчики получают события, поэтому он не подходит к каждой области в системе, чтобы заставить ее работать.

вы можете использовать angular-PubSub angular модуль. как только вы добавите модуль PubSub к зависимости вашего приложения, вы можете использовать службу PubSub для подписки и отмены подписки на события/темы.

Легко подписаться:

// Subscribe to event
var sub = PubSub.subscribe('event-name', function(topic, data){

});

Легко публиковать

PubSub.publish('event-name', {
    prop1: value1,
    prop2: value2
});

Чтобы отказаться от подписки, используйте PubSub.unsubscribe(sub); ИЛИ PubSub.unsubscribe('event-name');.

ПРИМЕЧАНИЕ Не забывайте отменять подписку, чтобы избежать утечек памяти.

1

Использовать RxJS в службе

Как насчет ситуации, когда у вас есть Служба, которая удерживает состояние, например. Как я могу нажать на изменения в этой Службе, и другие случайные компоненты на странице должны знать о таком изменении? Борьба с решением этой проблемы в последнее время

Создайте сервис с RxJS Extensions для Angular.

<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/rx/dist/rx.all.js"></script>
<script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>
var app = angular.module('myApp', ['rx']);

app.factory("DataService", function(rx) {
  var subject = new rx.Subject(); 
  var data = "Initial";

  return {
      set: function set(d){
        data = d;
        subject.onNext(d);
      },
      get: function get() {
        return data;
      },
      subscribe: function (o) {
         return subject.subscribe(o);
      }
  };
});

Затем просто подпишитесь на изменения.

app.controller('displayCtrl', function(DataService) {
  var $ctrl = this;

  $ctrl.data = DataService.get();
  var subscription = DataService.subscribe(function onNext(d) {
      $ctrl.data = d;
  });

  this.$onDestroy = function() {
      subscription.dispose();
  };
});

Клиенты могут подписаться на изменения с помощью DataService.subscribe, и производители могут нажать изменения с помощью DataService.set.

DEMO на PLNKR.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню