如何使用AngularJS进行$ http同步调用


132

有什么方法可以使用AngularJS进行同步调用吗?

AngularJS文档不是很明确,也不是为了找出一些基本内容而扩展。

在服务上:

myService.getByID = function (id) {
    var retval = null;

    $http({
        url: "/CO/api/products/" + id,
        method: "GET"
    }).success(function (data, status, headers, config) {

        retval = data.Data;

    });

    return retval;
}

另请参阅groups.google.com/d/topic/angular/qagzXXhS_VI/discussion,以获取有关如何处理异步行为的一些想法:事件,$ watch,服务器端预加载,使用从$ http返回的承诺。
Mark Rajcok 2012年

1
异步总是更好,特别是在您有诺言的时候。
安德鲁·乔斯林

很多时候,您可以避免同步呼叫。请参阅$ resource的工作原理stackoverflow.com/questions/11966252/…
honzajde

3
当您需要订购交货时,@ AndrewJoslin异步会更糟。
Stijn Van Antwerpen

Answers:


113

不是现在。如果查看源代码(从2012年10月开始),您会发现对XHR open的调用实际上是硬编码为异步的(第三个参数为true):

 xhr.open(method, url, true);

您需要编写自己的执行同步调用的服务。通常,由于JavaScript执行的性质,您通常不需要这样做,最终会阻塞其他所有内容。

...但是..如果实际上需要阻止其他所有内容,也许您应该研究promises和$ q service。它使您可以等待一组异步操作完成,然后在完成所有操作后执行一些操作。我不知道您的用例是什么,但这可能值得一看。

除此之外,如果您打算自己动手,可以在这里找到有关如何进行同步和异步ajax调用的更多信息。

希望对您有所帮助。


12
能否请您编写代码段以实现使用$ q服务。我尝试了许多选项,但它以异步方式工作。
Venkat 2014年

1
在某些地方有意义,例如,仅当用户关闭浏览器时(onbeforeunload),如果要保存,则必须发送同步请求,另一种选择是显示对话框取消,然后重新启动窗口关闭?
Braulio

2
@Venkat:我知道这是一个较晚的答复,但是正如我在回答中所说,该呼叫将始终是“异步的”,您只需要使用$ q使其等待响应,然后在内部继续您的逻辑即可.then(callback)。是这样的:doSomething(); $http.get('/a/thing').then(doEverythingElse);
Ben Lesh 2014年


1
@BenLesh我对您投入的时间或任何人投入的时间并不感激。我可以随意拒绝您的回答,并说如果提供示例,这对我会有所帮助。我看到了您的答案,但对我没有帮助,所以我投了反对票,并关闭了标签页,然后回到Google尝试寻找对我更有用的答案。当有人否决您的答案并告诉您如何改善答案时,这不是世界末日。您愿意在不留下任何评论的情况下让我拒绝投票吗?只是说实话。
电路

12

我曾在一家与google maps自动完成功能和承诺相结合的工厂工作过,希望能为您服务。

http://jsfiddle.net/the_pianist2/vL9nkfe3/1/

您只需将此请求替换为出厂前的$ http incuida即可将此请求替换autocompleteService。

app.factory('Autocomplete', function($q, $http) {

和$ http请求与

 var deferred = $q.defer();
 $http.get('urlExample').
success(function(data, status, headers, config) {
     deferred.resolve(data);
}).
error(function(data, status, headers, config) {
     deferred.reject(status);
});
 return deferred.promise;

<div ng-app="myApp">
  <div ng-controller="myController">
  <input type="text" ng-model="search"></input>
  <div class="bs-example">
     <table class="table" >
        <thead>
           <tr>
              <th>#</th>
              <th>Description</th>
           </tr>
        </thead>
        <tbody>
           <tr ng-repeat="direction in directions">
              <td>{{$index}}</td>
              <td>{{direction.description}}</td>
           </tr>
        </tbody>
     </table>
  </div>

'use strict';
 var app = angular.module('myApp', []);

  app.factory('Autocomplete', function($q) {
    var get = function(search) {
    var deferred = $q.defer();
    var autocompleteService = new google.maps.places.AutocompleteService();
    autocompleteService.getPlacePredictions({
        input: search,
        types: ['geocode'],
        componentRestrictions: {
            country: 'ES'
        }
    }, function(predictions, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            deferred.resolve(predictions);
        } else {
            deferred.reject(status);
        }
    });
    return deferred.promise;
};

return {
    get: get
};
});

app.controller('myController', function($scope, Autocomplete) {
$scope.$watch('search', function(newValue, oldValue) {
    var promesa = Autocomplete.get(newValue);
    promesa.then(function(value) {
        $scope.directions = value;
    }, function(reason) {
        $scope.error = reason;
    });
 });

});

该问题本身应针对:

deferred.resolve(varResult); 

当您做得很好并且要求:

deferred.reject(error); 

当有错误时,然后:

return deferred.promise;

5
var EmployeeController = ["$scope", "EmployeeService",
        function ($scope, EmployeeService) {
            $scope.Employee = {};
            $scope.Save = function (Employee) {                
                if ($scope.EmployeeForm.$valid) {
                    EmployeeService
                        .Save(Employee)
                        .then(function (response) {
                            if (response.HasError) {
                                $scope.HasError = response.HasError;
                                $scope.ErrorMessage = response.ResponseMessage;
                            } else {

                            }
                        })
                        .catch(function (response) {

                        });
                }
            }
        }]


var EmployeeService = ["$http", "$q",
            function ($http, $q) {
                var self = this;

                self.Save = function (employee) {
                    var deferred = $q.defer();                
                    $http
                        .post("/api/EmployeeApi/Create", angular.toJson(employee))
                        .success(function (response, status, headers, config) {
                            deferred.resolve(response, status, headers, config);
                        })
                        .error(function (response, status, headers, config) {
                            deferred.reject(response, status, headers, config);
                        });

                    return deferred.promise;
                };

4

我最近遇到了一种情况,我想对由页面重新加载触发的$ http调用进行调用。我去的解决方案:

  1. 将两个调用封装到函数中
  2. 将第二个$ http调用作为回调传递给第二个函数
  3. 在apon .success中调用第二个函数

如果它是一个for循环,需要n次调用服务器呢?
mithun

2

这是一种可以异步执行并像平常一样管理事情的方法。一切仍然共享。您获得对要更新的对象的引用。每当您在服务中更新它时,它都会全局更新,而不必观察或返回承诺。这真的很不错,因为您可以从服务中更新基础对象,而无需重新绑定。以应有的方式使用Angular。我认为使$ http.get / post同步可能不是一个好主意。您会在脚本中看到明显的延迟。

app.factory('AssessmentSettingsService', ['$http', function($http) {
    //assessment is what I want to keep updating
    var settings = { assessment: null };

    return {
        getSettings: function () {
             //return settings so I can keep updating assessment and the
             //reference to settings will stay in tact
             return settings;
        },
        updateAssessment: function () {
            $http.get('/assessment/api/get/' + scan.assessmentId).success(function(response) {
                //I don't have to return a thing.  I just set the object.
                settings.assessment = response;
            });
        }
    };
}]);

    ...
        controller: ['$scope', '$http', 'AssessmentSettingsService', function ($scope, as) {
            $scope.settings = as.getSettings();
            //Look.  I can even update after I've already grabbed the object
            as.updateAssessment();

在视图中的某处:

<h1>{{settings.assessment.title}}</h1>

0

由于同步XHR不建议使用,因此最好不要依赖它。如果需要执行同步POST请求,则可以在服务内部使用以下帮助程序来模拟表单发布。

它通过创建带有隐藏输入的表单来工作,该表单将发布到指定的URL。

//Helper to create a hidden input
function createInput(name, value) {
  return angular
    .element('<input/>')
    .attr('type', 'hidden')
    .attr('name', name)
    .val(value);
}

//Post data
function post(url, data, params) {

    //Ensure data and params are an object
    data = data || {};
    params = params || {};

    //Serialize params
    const serialized = $httpParamSerializer(params);
    const query = serialized ? `?${serialized}` : '';

    //Create form
    const $form = angular
        .element('<form/>')
        .attr('action', `${url}${query}`)
        .attr('enctype', 'application/x-www-form-urlencoded')
        .attr('method', 'post');

    //Create hidden input data
    for (const key in data) {
        if (data.hasOwnProperty(key)) {
            const value = data[key];
            if (Array.isArray(value)) {
                for (const val of value) {
                    const $input = createInput(`${key}[]`, val);
                    $form.append($input);
                }
            }
            else {
                const $input = createInput(key, value);
                $form.append($input);
            }
        }
    }

    //Append form to body and submit
    angular.element(document).find('body').append($form);
    $form[0].submit();
    $form.remove();
}

根据需要进行修改。


-4

将调用包装在Promise.all()方法中怎么办

Promise.all([$http.get(url).then(function(result){....}, function(error){....}])

根据MDN

Promise.all等待所有实现(或第一个拒绝)


你在说什么?这个问题与多重承诺无关...
Ovidiu Dolha

它将等待一个或多个诺言完成!
Manjit Dosanjh

您是否曾用它来查看其工作原理?Promise.all将返回另一个诺言,它不会将异步转换为同步调用
Ovidiu Dolha

嗯...似乎MDN文档可能含糊不清...实际上并没有按照其文档中的说明等待。
Manjit Dosanjh

欢迎来到SO。请阅读此操作指南以提供优质的答案。
thewaywere是
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.