Подтвердить что ты не робот

AngularJS $на порядок запуска обработчика событий

Мне было интересно две вещи, в контексте обработки событий angularJS.

  • Как определяется порядок, в котором запускаются обработчики, прослушивающие одно и то же событие?
  • Является ли это признаком плохого дизайна, если вы начинаете задумываться об этом?

После чтения документации по angular $on, $broadcast и $emit, а также встроенного потока событий DOM Думаю, я понимаю, в каком порядке обработчики событий будут запускаться в разных областях. Проблема заключается в том, что несколько обработчиков прослушиваются в одной области (например, $rootScope) из разных мест (например, Controllers vs Services).

Чтобы проиллюстрировать проблему, я собрал jsfiddle с одним контроллером и двумя службами, все из которых передаются через $rootScope http://jsfiddle.net/Z84tX/

Thanks

4b9b3361

Ответ 1

Очень хороший вопрос.

Обработчики событий выполняются в порядке инициализации.

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

У вас есть контроллер controllerA, который зависит от двух сервисов, ServiceA и ServiceB:

myModule
  .controller('ControllerA', 
    [
      '$scope', 
      '$rootScope', 
      'ServiceA', 
      'ServiceB', 
      function($scope, $rootScope, ServiceA, ServiceB) {...}
    ]
  );

Обе службы и контроллер определяют прослушиватель событий.

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

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

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

Итак, конечный результат: в $broadcast обработчики будут выполняться в следующем порядке: ServiceA обработчик, обработчик ServiceB, обработчик controllerA.

Ответ 2

Это немного беспорядочно (и я бы не рекомендовал его), чтобы идти по этому маршруту, но хотел предоставить альтернативный вариант, когда вы не можете гарантировать, что serviceB будет инициализирован до службы A, и вам абсолютно необходимо, чтобы прослушиватель serviceB выполнялся первым.

Вы можете манипулировать массивом $rootScope.$$listeners, чтобы сначала включить прослушиватель serviceB.

Что-то вроде этого будет работать при добавлении слушателя к $rootScope в serviceB:

var listener, listenersArray;
$rootScope.$on('$stateChangeStart', someFunction);
listenersArray = $rootScope.$$listeners.$stateChangeStart;
listener = listenersArray[listenersArray.length - 1];
listenersArray.splice(listenersArray.length - 1, 1);
listenersArray.unshift(listener);

Ответ 3

Чтобы дать ответ на # 2 (потому что я думаю, что ответ @Stewie на # 1 действительно хороший), в то время как я бы колебался когда-либо предлагать убедительные правила, которые говорят: "Если вы видите это, то это плохой код", Я бы сказал, что если у вас есть два обработчика событий, и можно выполнить только после запуска другого: вы должны оценить, почему это так, и если вы не можете лучше инкапсулировать или организовать способ выполнения вашей логики.

Одним из основных случаев использования вещания/прослушивания pub/sub event является предоставление отдельным компонентам, которые полностью независимы друг от друга для асинхронного использования в своей области влияния независимым образом. Посредством одного обработчика, который должен работать только после первого запуска другого обработчика, вы удаляете асинхронный характер pub/sub, добавляя дополнительное требование (хотя, возможно, необходимо).

Если это абсолютно необходимая зависимость, то нет: это не симптом плохого дизайна - это признак требований этой функции.

Ответ 4

Я новый пользователь для Angular JS, поэтому, пожалуйста, простите, если ответ менее оптимальный.: P

Если вам требуется порядок функций, инициируемых зависящим от события (т.е. функция A, затем функция B), то может быть лучше не создавать функцию триггера?

function trigger(event,data) {
    FunctionA(event,data);
    FunctionB(event,data);
}

$rootScope.on('eventTrigger',trigger);

Ответ 5

Чтобы добавить еще один комментарий к точке # 2, если вам нужно гарантировать заказ, вы можете реализовать шаблон наблюдателя, используя службу с массивом слушателей. В сервисе вы можете определить функции addListener, которые также определяют порядок упорядочивания слушателей. Затем вы можете применить эту услугу к другим компонентам, которые должны запускать события.