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

7 回答 7

114

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

 xhr.open(method, url, true);

您需要编写自己的服务来进行同步调用。通常这不是你通常想做的事情,因为 JavaScript 执行的性质你最终会阻塞其他一切。

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

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

我希望这会有所帮助。

于 2012-10-26T14:00:52.260 回答
12

我曾与一家集成了谷歌地图自动完成和承诺的工厂合作过,我希望你能服务。

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;
于 2014-06-26T08:57:26.003 回答
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;
                };
于 2015-09-04T10:37:43.543 回答
4

我最近遇到了一种情况,我想通过页面重新加载触发 $http 调用。我采用的解决方案:

  1. 将两个调用封装成函数
  2. 将第二个 $http 调用作为回调传递给第二个函数
  3. 调用 apon .success 中的第二个函数
于 2015-07-21T15:01:20.603 回答
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>
于 2016-02-02T13:51:11.543 回答
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();
}

根据您的需要进行修改。

于 2018-03-12T07:35:47.230 回答
-4

将您的呼叫包装在一个Promise.all()方法中怎么样?

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

根据MDN

Promise.all 等待所有的履行(或第一次拒绝)

于 2017-05-24T13:23:56.857 回答