例如,让我们假设我需要在收到两个事件后运行一个函数" 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... */
};
如果有三个或更多事件,这会变得更复杂。是否有设计模式来处理这些情况?
答案 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)
一种方法:
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
带有一个承诺的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();
}
]);
承诺就是生命。
答案 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();
}
}
});