如何使用getter和setter方法创建Angular工厂而不会遇到竞争条件

时间:2016-01-12 07:32:42

标签: javascript angularjs restangular

我创建工厂以从一个页面获取userId,调用REST API,并在以下视图中返回结果。我最初的尝试主要来自this answer但是 - 毫不奇怪 - 我一直处于不及时响应并且get()方法返回空数组的情况下。

这是工厂本身

app.factory('GetMessages', function() {
 var messages = []

 function set(userId) {

   Restangular.all('/api/messages/').getList({'_id': userId}).then(function(docs){
    messages = docs   
    })
 }

 function get() {
    return messages;
 }

 return {
  set: set,
  get: get
 }

});

对于它的价值,我可以毫不费力地将userId带入工厂,因为它只是传递了这样的功能

视图:

<a ng-click='passToFactory(message.user.id)' href='/home/inbox/reply'>Reply</a>

控制器:

$scope.passToFactory = function(id) {
    GetMessages.set(id);
};

以下视图的控制器就是 $scope.messages = GetMessages.get()

我遇到的问题是,在工厂返回空集后,不会识别出工厂的进一步更改(即使经过一段时间后它确实从API获得了正确的响应)并且$scope.messages仍然是空的。

我试图将API调用移到get方法(由于get方法通常无法及时获得userId,因此无法运行)我无法做到找到一种方法来使用承诺强制get()等待set()完成。

我更喜欢在最终的解决方案中继续使用Restangular,但这是一件小事,因为任何修复工作都需要花费太多时间。

我对Angular相当陌生,所以我确定有一些非常明显的东西,但现在我只是输了。感谢。

4 个答案:

答案 0 :(得分:1)

你遇到的竞争条件是.then方法中的函数在调用set函数后异步执行。如果get函数在<{strong>之前执行<{1}}服务执行承诺时执行,则get函数返回一个空数组。

解决方案是从承诺中保存承诺

$q

在您的控制器中,来自承诺的

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

 var promise;

 function set(userId) {

     promise = Restangular.all('/api/messages/').getList({'_id': userId});
 }

 function get() {
    return promise;
 }

 return {
  set: set,
  get: get
 }

});

有关链接承诺的详情,请参阅AngularJS $q Service API Reference -- chaining promises

答案 1 :(得分:0)

重新分配时,您正在断开对原始messages数组的引用。

尝试:

Restangular.all('/api/messages/').getList({'_id': userId}).then(function(docs){
    messages.concat(docs) ; // keep same array reference   
});

简单的例子来解释它为什么不起作用

var arr = [];
var x   = arr;
arr     = [1,2,3]; // is now a different array reference
console.log(x); // is still empty array. x !== arr now 

答案 2 :(得分:0)

cherlietfl是对的。

问题是你破坏了对messages数组的引用,因为你为get函数中的消息分配了一个新数组。但是concat也是这样做的。

试试这个:

Restangular.all('/api/messages/').getList({'_id': userId}).then(function(docs){
  messages.splice(0, messages.length); // clear the array
  messages.push.apply(messages, docs); //add the new content
});

答案 3 :(得分:0)

尝试将功能分配给范围。然后在模型中调用该函数。像这样:

// controller
$scope.getMessages = GetMessages.get;

查看:

<div ng-repeat="message in getMessages()"></div>

这样,当请求调用完成并且摘要周期再次通过观察者时,将调用get函数,您将收到消息。