【问题标题】:Node.js + Angular.js promises sync issueNode.js + Angular.js 承诺同步问题
【发布时间】:2017-05-15 12:43:15
【问题描述】:

我正在开发一个聊天应用程序,它是服务器端的 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”和“dave”)。

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

  1. 如果房间不存在则创建房间
  2. 将该用户推入房间的 users 数组。

我知道,因为 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 将链接。位置路径将在两个 XHR 完成之前更改。当您说“第二个动作发生在第一个动作之前”时,您是在谈论 XHR 没有链接还是在 XHR 完成之前位置发生变化?
  • 我说的是 XHR 没有链接
  • 旁注:您可能想先尝试简单地将用户添加到房间,然后仅在第一次调用失败时才尝试创建房间。它将完全消除对is_room_already_exists 函数的需求。
  • 其次,您可能需要调整 /register_room 的服务器端路由,使其也采用用户名。然后您可以自动将正在注册房间的用户添加到该房间服务器端,从而消除来自客户端的额外请求。

标签: angularjs node.js mongodb angular-promise


【解决方案1】:

试试这个:

$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
            });
        }

【讨论】:

  • 谢谢,但还是没有运气。我向客户端添加了日志记录,我看到了这个顺序:is_room_already_exists、add_user_to_room_request、register_room。它应该在哪里: is_room_already_exists register_room add_user_to_room_request
  • @Matoy 我提供的代码根本不可能。
  • 你是对的。对不起。你的解决方案是正确的。我的代码没有在服务器上正确刷新。谢谢!
【解决方案2】:

我说的是 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;
}

如果正确返回了一个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 链。可以创建任意长度的链,并且由于可以使用另一个 Promise 来解决一个 Promise(这将进一步推迟其解决方案),因此可以在任何时候暂停/延迟解决 Promise连锁,链条。这使得实现强大的 API 成为可能。

-- AngularJS $q Service API Reference - Chaining Promises.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 2017-01-13
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多