synchronous http call in angularJS

2019-03-10 19:45发布

问题:

I have the following scenario, I need data from a particular url. I have written a function which takes parameter 'url'. Inside the function I have the $http.get method which makes a call to the url. The data is to be returned to the calling function

var getData = function (url) {
    var data = "";

    $http.get(url)
        .success( function(response, status, headers, config) {
             data = response;
        })
        .error(function(errResp) {
             console.log("error fetching url");
        });
    return data;
}

The problem is as follows, $http.get is asynchronous, before the response is fetched, the function returns. Therefore the calling function gets the data as empty string. How do I force the function not to return until the data has been fetched from the url?

回答1:

Take a look at promises to overcome such issues, because they are used all over the place, in angular world.

You need to use $q

var getData = function (url) {
    var data = "";
    var deferred = $q.defer();

    $http.get(url)
        .success( function(response, status, headers, config) {
             deferred.resolve(response);
        })
        .error(function(errResp) {
             deferred.reject({ message: "Really bad" });
        });
    return deferred.promise;
}

Here's a nice article on promises and $q

UPDATE:

FYI, $http service itself returns a promise, so $q is not necessarily required in this scenario(and hence an anti-pattern).

But do not let this be the reason to skip reading about $q and promises.

So the above code is equivalent to following:

var getData = function (url) {
    var data = "";
    return $http.get(url);
}


回答2:

You can use $q.all() method also to solve this problem

var requestPromise = [];

var getData = function (url) {
    var data = "";

    var httpPromise = $http.get(url)
        .success( function(response, status, headers, config) {
             data = response;
        })
        .error(function(errResp) {
             console.log("error fetching url");
        });

    requestPromise.push(httpPromise);
}

in the calling function

$q.all(requestPromise).then(function(data) {

    //this is entered only after http.get is successful
});

make sure to inject $q as a dependency. Hope it helps



回答3:

A typical way to do what you want is like so:

var getData = function(url, callback) {
    $http.get(url).success(function(response) {
        callback && callback(response);
    });
};

Used like:

getData('/endpoint', function(data) {
    console.log(data);
});


回答4:

You function seems redundant. Just use $http.get(url), since you aren't really doing anything else before you use it anyway.

var url = 'foo/bar';

$http
    .get(url)
    .success( function(response, status, headers, config) {
        $scope.data = response;
    })
    .error(function(errResp) {
        console.log("error fetching url");
    });

Or if you need to access the promise later just assign it to variable;

var promise = $http.get(url);

// some other code..

promise.then(function(data){
   //.. do something with data
});