如何在收到两个或更多$ scope事件后调用函数?

时间:2014-12-18 02:18:24

标签: angularjs

例如,让我们假设我需要在收到两个事件后运行一个函数" eventA"和" eventB"。我通常做的是为每个事件声明一个布尔变量,在收到事件时将变量设置为true,并询问另一个变量是否为true来运行该函数:

var a = false, 
    b = false;

$scope.$on("eventA", function(){
    a = true;
    if (b)
        performTask();
});

$scope.$on("eventB", function(){
    b = true;
    if (a)
        performTask();
});

var performTask = function() {
    /* do something... */
};

如果有三个或更多事件,这会变得更复杂。是否有设计模式来处理这些情况?

4 个答案:

答案 0 :(得分:3)

你可以使用$ q promises。

var dfdATask= $q.defer();
var dfdBTask= $q.defer();

$scope.$on("eventA", function(){
    // whatever this function does
    dfdATask.resolve(true);//or pass a value
});

$scope.$on("eventB", function(){
    //whatever this function does
    dfdBTask.resolve(true);//or pass a value
});

$q.all([dfdATask.promise, dfdBTask.promise]).then(function(){
    //be sure to pass in an array of promises
    //perform task
})

答案 1 :(得分:1)

使用$ scope进行活动轮询。$ watch:

一种方法:

var a = false, b = false;
$scope.$on("eventA", function(){ a = true; });
$scope.$on("eventB", function(){ b = true; });
$scope.$watch(
   function() { return a && b; },
   function(newval, oldval) {
      if (newval) { performTask(); }
   }
);

更进一步:

var events = { a: false, b: false };
$scope.$on("eventA", function(){ events.a = true; });
$scope.$on("eventB", function(){ events.b = true; });
$scope.$watch(
   function() {
      var result = true;
      for (var key in events) {
         result = result && events[key]; 
      }
      return result;
   },
   function(newval, oldval) {
      if (newval) { performTask(); }
   }
);

http://plnkr.co/edit/5NrOhTwblMCCCoKncVAW?p=preview

务必阅读developer guide并查看“Scope $ watch Performance Considerations”部分。

常规回调:

var events = { a: false, b: false };
function checkIfPerfomTask() {
   for (var key in events) {
      if (!events[key]) { return; }
   }
   performTask();
}
$scope.$on("eventA", function(){ events.a = true; checkIfPerfomTask(); });
$scope.$on("eventB", function(){ events.b = true; checkIfPerfomTask(); });

http://plnkr.co/edit/5NrOhTwblMCCCoKncVAW?p=preview

带有一个承诺的

,$ q.defer():

var events = { a: false, b: false };
var shouldPerform = $q.defer();
function checkIfPerfomTask() {
   for (var key in events) {
      if (!events[key]) { return; }
   }
   shouldPerform.resolve();
}

$scope.$on("eventA", function(){ events.a = true; checkIfPerfomTask(); });
$scope.$on("eventB", function(){ events.b = true; checkIfPerfomTask(); });
shouldPerform.promise.then(performTask);

http://plnkr.co/edit/5NrOhTwblMCCCoKncVAW?p=preview

有多个承诺......

已经有多个答案。

答案 2 :(得分:1)

理论上明智的是,如果你只是想在你收到这两个事件之后执行这个神奇的动作,那么你至少会被召唤一次然后你可能想要使用承诺。

app.controller('ExampleOneController', [
    '$log',
    '$scope',
    '$q',
    '$rootScope',

    function ($log, $scope, $q, $rootScope) {
        $scope.anotherAction1FiredCount = 0;

        var aDeferred = $q.defer(),
            bDeferred = $q.defer();

        $scope.$on('e-1-a', function () {
            $log.log('Fired e-1-a');
            aDeferred.resolve();
        });

        $scope.$on('e-1-b', function () {
            $log.log('Fired e-1-b');
            bDeferred.resolve();
        });

        $q.all([aDeferred.promise, bDeferred.promise]).then(function () {
            $log.log('Fired another action 1!');
            $scope.anotherAction1 = 'Hello World 1!';

            $scope.anotherAction1FiredCount++;
        });
    }
]);

通常情况下,我希望每次发生两件事时都要执行,所以我倾向于重置'我的承诺。

app.controller('ExampleTwoController', [
    '$log',
    '$scope',
    '$q',

    function ($log, $scope, $q) {
        $scope.anotherAction2FiredCount = 0;

        var aDeferred = $q.defer(),
            bDeferred = $q.defer();

        $scope.$on('e-2-a', function () {
            $log.log('Fired e-2-a');
            aDeferred.resolve();
        });

        $scope.$on('e-2-b', function () {
            $log.log('Fired e-2-b');
            bDeferred.resolve();
        });

        var wait = function () {
            $q.all([aDeferred.promise, bDeferred.promise]).then(function () {
                $log.log('Fired another action 2!');
                $scope.anotherAction2 = 'Hello World 2!';
                $scope.anotherAction2FiredCount++;

                aDeferred = $q.defer();
                bDeferred = $q.defer();
                wait();
            });
        };
        wait();
    }
]);

Here's the working plunker!

  

承诺就是生命。

答案 3 :(得分:0)

Promise适用于您的用例。但既然你提到你正在寻找一种设计模式,我会用Observer模式做出一种方法。

你可以查看这个真实的Plunkr:http://plnkr.co/edit/1Oqn2TAGTr7NLYZd9ax1?p=preview

有一个angularjs服务,用于处理跟踪事件和调用最终操作的逻辑。

控制器只是定义您的事件,最终事件并将其注册到您的服务中。

app.controller('MainCtrl', function($scope, EventService) {
  var events = [];

  ... //define events

  EventService.registerEvents(events);
  EventService.registerEventsCallback(finalEvent); //the observer

});

该服务通过首次执行时从事件列表中删除被调用事件来实现此功能。

app.factory('EventService', function(){

  var events = [];
  var finalEvent;

  var eventsCallback = function(){
    if(!events.length){
      finalEvent();
    }
  }

  var resolveEvent= function(event){
      var eventIndex = events.indexOf(event);
      if(eventIndex>=0){
        events.splice(eventIndex,1);
      }
  }
  return{
    registerEvents: function(eventsList){
      events = angular.copy(eventsList);
    },
    registerEventsCallback: function(event){
      finalEvent = event;
    },
    publishEvent: function(event){

      event();

      resolveEvent(event);

      eventsCallback();
    }
  }
});