Node.js+Angular.js承诺同步问题



我正在开发一个聊天应用程序,服务器端是Node.js+MongoDB(Mongoose库),客户端是Angular.js。

我有一个房间(应用程序中的所有房间)的数据库集合(MongoDB),看起来像这样:

// ------- creating active_rooms model -------
var active_rooms_schema = mongoose.Schema({
room_name: String,
users: [String]
});
var active_rooms = mongoose.model('active_rooms', active_rooms_schema);

该数据库包含一个包含所有用户的房间(即"我的酷房间",其中包含用户:"mike"、"joe"one_answers"dave")。

我想做的是——每次用户想在我的Angular.js客户端的聊天室(有一些房间名称)时,我都想:

  1. 如果房间不存在,则创建该房间
  2. 将该用户推送到房间的用户阵列中

我知道,由于1,我将始终拥有一个包含用户阵列的房间。

这是我的Angular相关代码:(我不能在这里给出整个应用程序,因为它太大了,不相关。)

$scope.enterRoom = function(info) {
$q.when(create_room_if_not_exists($scope.room)).then(add_user_to_room($scope.name, $scope.room));
$location.path("chat");
}

var create_room_if_not_exists = function(room_name) {
var deferred = $q.defer();
is_room_already_exists({
'name': room_name
}).then(function(response) {
if (!response.data.is_room_exists) {
register_room({
'name': room_name
});
console.log("room: " + room_name + ", was created");
deferred.resolve();
}
}, function(error) {
deferred.reject(error.data);
});
return deferred.promise;
}
var add_user_to_room = function(user_name, room_name) {
console.log(user_name)
add_user_to_room_request({
'user_name': user_name,
'room_name': room_name
});
}
var is_room_already_exists = function(info) {
return $http({
url: '/is_room_already_exists',
method: 'POST',
data: info
});
}
var add_user_to_room_request = function(info) {
$http({
url: '/add_user_to_room',
method: 'POST',
data: info
});
}
var register_room = function(info) {
return $http({
url: '/register_room',
method: 'POST',
data: info
});
}

第二个动作发生在第一个动作之前。当我在控制台中打印日志时,我看到了这一点,我不知道为什么。

这两个操作都是通过对服务器的HTTP请求到达的,所以我认为问题不存在。

我说的是没有链接的XHR

链接问题的一个常见原因是未能向链返回承诺:

var add_user_to_room = function(user_name, room_name) {
console.log(user_name)
//add_user_to_room_request({
return add_user_to_room_request({
//^^^^^^ ----- be sure to return returned promise
'user_name': user_name,
'room_name': room_name
});
}

如果链接操作正确,则不需要$q.defer

var create_room_if_not_exists = function(room_name) {
//var deferred = $q.defer();
//is_room_already_exists({
return is_room_already_exists({
//^^^^^^ --- be sure to return derived promise
'name': room_name
}).then(function(response) {
if (!response.data.is_room_exists) {
console.log("room: " + room_name + ", to be created");
//register_room({
return register_room({
//^^^^^^ ----- return promise to further chain
'name': room_name
});
//deferred.resolve();
} else {
return room_name;
//^^^^^^ ----- return to chain data
};
}, function(error) {
//deferred.reject(error.data);
throw error;
//^^^^^ ------- throw to chain rejection
});
//return deferred.promise;
}

如果承诺正确返回,则不需要$q.when

$scope.enterRoom = function(info) {
//$q.when(create_room_if_not_exists($scope.room))
//   .then(add_user_to_room($scope.name, $scope.room));
return create_room_if_not_exists($scope.room)
.then(function() {
return add_user_to_room($scope.name, $scope.room));
}).then(function()
$location.path("chat")
});
}

函数式编程的经验法则是--总是返回一些东西

因为调用promise的.then方法会返回一个新的派生promise,所以很容易创建一个promise链。可以创建任何长度的链,并且由于一个承诺可以用另一个承诺来解决(这将进一步推迟其解决),因此可以在链中的任何点暂停/推迟承诺的解决。这使得实现强大的API成为可能

--AngularJS$q服务API参考-链接承诺。

试试这个:

$scope.enterRoom = function (info) {
return create_room_if_not_exists($scope.room)).then(function(){
return add_user_to_room_request({ 'user_name': $scope.name, 'room_name': $scope.name });
}).then(function(){
$location.path('chat');
});
}

var create_room_if_not_exists = function (room_name) {
var deferred = $q.defer();
return is_room_already_exists({ 'name': room_name }).then(function (response) {
if (!response.data.is_room_exists) {
console.log("room: " + room_name + ", is being created");
return register_room({ 'name': room_name });
}
return response;
})
}
var is_room_already_exists = function (info) {
return $http({
url: '/is_room_already_exists',
method: 'POST',
data: info
});
}
var add_user_to_room_request = function (info) {
return $http({
url: '/add_user_to_room',
method: 'POST',
data: info
});
}
var register_room = function (info) {
return $http({
url: '/register_room',
method: 'POST',
data: info
});
}

最新更新