0

I have the following service:

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

When I am calling it, I first get the error because the service returns nothing according to console printouts just before return (see below in). Only after that I see printout on the console that $http was success and the pfList.lenght is 109 (see below).

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  <---------------

Seems like a race condition here. Why is this happening and how to fix it? Thanks.

1
  • typical javascript (without any sort of workers) runs in a single thread, I don't think it's related to race condition Commented Nov 3, 2015 at 4:04

1 Answer 1

2

I think you are making things unnecessarily complicated.

$http returns a promise itself, so just return that from the function and you won't need to the $q or the weird timeout. See below

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

The reason the first console.log had no data was because it wasn't in the then block so it executes before the $http call has chance to finish.

If you were using the above code to chain events you'd use it like so

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

If you are certain on making the promise return the data in the function you could alter your code like so:

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

Final note: if you specify to the http call that you expect JSON you won't need to parse it afterwards

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.