如何 $http 同步调用 AngularJS

有没有办法用 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;
}
202986 次浏览

目前没有。如果使用 查看源代码(从2012年10月的这个时间点开始),您将看到对 XHR open 的调用实际上被硬编码为异步的(第三个参数为 true) :

 xhr.open(method, url, true);

您需要编写自己的同步调用服务。通常情况下,这不是您通常想要做的事情,因为 JavaScript 执行的性质最终会阻塞其他所有内容。

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

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

我希望这对你有帮助。

我曾与一个工厂集成谷歌地图自动完成和承诺,我希望你的服务。

Http://jsfiddle.net/the_pianist2/vl9nkfe3/1/

您只需要通过此请求替换 autoCompleteService,并且 $http incuida 位于工厂之前。

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;

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

  1. 将这两个调用封装为函数
  2. 将第二个 $http 调用作为回调传递给第二个函数
  3. 调用 apon 中的第二个函数
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;
};

这里有一个方法,你可以异步进行,像平常一样管理事情。 一切都是共享的。您将获得对要更新的对象的引用。无论何时你在你的服务中更新它,它都会在全球范围内更新,而不需要观察或者返回一个承诺。 这非常好,因为您可以从服务内部更新底层对象,而无需重新绑定。使用角度的方式,它的意思是使用。 我认为同步 $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>

将调用封装在 Promise.all()方法中如何。

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

根据 MDN

All 等待所有的实现(或者第一次拒绝)

由于 同步 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();
}

根据需要进行修改。