AngularJS中$http的竞争条件

Race condition with $http in AngularJS

本文关键字:竞争 条件 http AngularJS      更新时间:2023-09-26

我有以下服务:

app.factory('ParserWebService', function($http, $q, $timeout){
    ParserWebService.getParserPfList = function() {
        var pfData = $q.defer();
        var pfList = [];
        $http.get("https://myurl/parserpf")
            .then(function(response) {
                var reponseDataJSON = JSON.parse(response.data);
                for (var el in reponseDataJSON) {
                    if (reponseDataJSON[el].pf.length > 0) {  // Check for non-empty string
                        pfList.push(reponseDataJSON[el]);
                    }
                }
console.log("http GET SUCCESS");
console.log("pfList.length: " + pfList.length);
            })
            .catch(function(response) {
                console.error('GET error', response.status, response.data);
            })
console.log(pfList[0]);
        $timeout(function(){
            pfData.resolve(pfList);
        },1000);
console.log("pfList.length: " + pfList.length);
console.log("pfData.promise.length: " + pfData.promise.length);
        return pfData.promise;
    }
  return ParserWebService;
});

当我调用它时,我首先得到错误,因为在返回之前,服务根据控制台打印输出不返回任何内容(请参阅中的)。只有在那之后,我才在控制台上看到$http成功的打印输出,pfList.lenght是109(见下文)。

pfList.length: 0            <------------------
pfData.promise.length: undefined        <----------------
mopidId = 0, id = null
angular.js:11607 TypeError: Cannot read property 'id' of undefined
    at new <anonymous> (controllers.js:32)
    at Object.e [as invoke] (angular.js:4185)
    at $get.w.instance (angular.js:8454)
    at angular.js:7700
    at s (angular.js:331)
    at A (angular.js:7699)
    at g (angular.js:7078)
    at g (angular.js:7081)
    at g (angular.js:7081)
    at angular.js:6957(anonymous function) @ angular.js:11607$get @ angular.js:8557$get.l.$apply @ angular.js:14502(anonymous function) @ angular.js:1448e @ angular.js:4185d @ angular.js:1446tc @ angular.js:1466Jd @ angular.js:1360(anonymous function) @ angular.js:26176m.Callbacks.j @ jquery.js:3148m.Callbacks.k.fireWith @ jquery.js:3260m.extend.ready @ jquery.js:3472J @ jquery.js:3503
models.js:599 http GET SUCCESS   <---------------
models.js:600 pfList.length: 109  <---------------

这似乎是一种种族状况。为什么会发生这种情况,以及如何解决?谢谢

我认为你让事情变得不必要的复杂。

$http本身返回一个promise,所以只需从函数中返回它,就不需要$q或奇怪的超时。见下文

app.factory('ParserWebService', function($http){
    ParserWebService.pfList=[];
    ParserWebService.getParserPfList = function() {
        return $http.get("https://myurl/parserpf")
            .then(function(response) {
                var reponseDataJSON = JSON.parse(response.data);
                for (var el in reponseDataJSON) {
                    if (reponseDataJSON[el].pf.length > 0) {  // Check for non-empty string
                        ParserWebService.pfList.push(reponseDataJSON[el]);
                    }
                }
            })
            .catch(function(response) {
                console.error('GET error', response.status, response.data);
            })
    }
  return ParserWebService;
});

第一个console.log没有数据的原因是它不在then块中,所以它在$http调用有机会完成之前执行。

如果你使用上面的代码来链接事件,你会像一样使用它

ParserWebService.getParserPfList.then(function(){
    console.log("All the data is here: ",ParserWebService.pfList);
})

如果你确定要让承诺返回函数中的数据,你可以这样修改你的代码:

ParserWebService.getParserPfList = function() {
    var pfData = $q.defer();
    var pfList = [];
    $http.get("https://myurl/parserpf")
        .then(function(response) {
            var reponseDataJSON = JSON.parse(response.data);
            for (var el in reponseDataJSON) {
                if (reponseDataJSON[el].pf.length > 0) {  // Check for non-empty string
                    pfList.push(reponseDataJSON[el]);
                }
            }
            pfData.resolve(pfList);
        })
        .catch(function(response) {
            console.error('GET error', response.status, response.data);
            pfData.reject();
        })
    return pfData.promise;
}

最后注意:如果您为http调用指定了期望的JSON,则无需在

之后对其进行解析