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

How can I create an Angular factory with a getter and setter method without running into a race condition

本文关键字:工厂 Angular 一个 不遇 条件 竞争 遇到 getter 何使用 setter 方法      更新时间:2023-09-26

我正在创建一个工厂,从一个页面中获取用户ID,调用REST API,并在下面的视图中返回结果。我最初的尝试很大程度上是根据这个答案进行的,但不出所料,我一直处于这样一种情况:没有及时响应,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),并且我找不到使用promise强制get()等待set()完成的方法。

我更愿意在最终的解决方案中继续使用Restangular,但这是一件花费了太多时间的小事,所以任何修复都有效。

我是Angular的新手,所以我相信有一些非常明显的东西,但现在我只是迷失了方向。谢谢

您的竞争条件是.then方法中的函数在调用set函数后异步执行。如果get函数在$q服务实现承诺之前执行,那么get函数将返回一个空数组。

解决方案是从promise中保存promise

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

在您的控制器中,从承诺链接

GetMessages.get.then( function (docs) {
    $scope.messages = docs;
}) .catch ( function (error) {
    //log error
};

有关链接承诺的更多信息,请参阅AngularJS$q服务API参考——链接承诺。

重新分配时,您正在破坏对原始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 

cherlietfl是对的。

问题是,由于在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
});

尝试将函数分配给作用域。然后在模型中调用该函数。像这样:

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

视图:

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

这样,当请求调用完成,摘要循环再次通过观察者时,将调用get函数,您将获得消息。