javascript 如何在 AngularJS 控制器中发出同步 AJAX 请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30745116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make synchronous AJAX requests in AngularJS controller
提问by lys1030
I've been told that $http in Angular is asynchronous. However, for some purpose, I need to make sequential AJAX requests. I want to read all the files from a file list, and then get the number from all those files. For example:
有人告诉我 Angular 中的 $http 是异步的。但是,出于某种目的,我需要发出连续的 AJAX 请求。我想从文件列表中读取所有文件,然后从所有这些文件中获取编号。例如:
content of "fileNames":
“文件名”的内容:
file1
file2
content of "file1":
“文件 1”的内容:
1
content of "file2":
“文件2”的内容:
2
The following code will calculate the sum
以下代码将计算总和
<!DOCTYPE html>
<html>
<body>
<p id="id01"></p>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
var fileString;
/* first AJAX call */
$.ajax({
url: 'fileNames', type: 'get', async: false,
success: function(content) {
fileString = content;
}
});
var fileList = fileString.split('\n');
var sum = 0;
for (var i = 0; i < fileList.length; i++) {
/* second AJAX call in getNumber function */
sum += getNumber(fileList[i]);
}
document.getElementById("id01").innerHTML = sum;
function getNumber(file) {
var num;
$.ajax({url: file, type: 'get', async: false,
success: function(content) {
num = content;
}
});
return parseInt(num);
}
</script>
</body>
</html>
Since the two $.ajax calls are sequential, I don't know how to achieve this functionality in AngularJS. Say, in the end, I want $scope.sum = 1 + 2.
由于两次$.ajax调用是连续的,不知道AngularJS中如何实现这个功能。说,最后,我想要 $scope.sum = 1 + 2。
Can someone make it work in AngularJS? Some simple code would be appreciated!
有人可以让它在 AngularJS 中工作吗?一些简单的代码将不胜感激!
采纳答案by PSL
You could make use of promises and promise chaining (with $q
and the promise returned by $http
). Example: In your controller you could do (after injecting $http
, $q
):
您可以使用 promise 和 promise 链接(with$q
和返回的 promise $http
)。示例:在您的控制器中,您可以执行以下操作(注入$http
, 后$q
):
angular.module('myApp').controller('MyCtrl', ['$http','$q','$scope', function($http, $q, $scope){
function getData(){
//return promise from initial call
return $http.get('fileNames')
.then(processFile) //once that is done call to process each file
.then(calculateSum);// return sum calculation
}
function processFile(response){
var fileList = response.data.split('\n');
//Use $q.all to catch all fulfill array of promises
return $q.all(fileList.map(function(file){
return getNumber(file);
}));
}
function getNumber(file) {
//return promise of the specific file response and converting its value to int
return $http.get(file).then(function(response){
return parseInt(response.data, 10);
});
//if the call fails may be you want to return 0? then use below
/* return $http.get(file).then(function(response){
return parseInt(response.data, 10);
},function(){ return 0 });*/
}
function calculateSum(arrNum){
return arrNum.reduce(function(n1,n2){
return n1 + n2;
});
}
getData().then(function(sum){
$scope.sum = sum;
}).catch(function(){
//Oops one of more file load call failed
});
}]);
Also see:
另见:
- $http
- $q
- $q.all
- Array.map- You could as well manually loop though the array and push promise to array.
- Array.reduce- You could as well loop through number and add them up.
- $http
- $q
- $q.all
- Array.map- 您也可以手动遍历数组并将承诺推送到数组。
- Array.reduce- 您也可以遍历数字并将它们相加。
This does not mean that the calls are synchronous, but they are asynchronous and still does what you need in a more efficient way and easy to manage.
这并不意味着调用是同步的,但它们是异步的,并且仍然以更有效且易于管理的方式执行您需要的操作。
回答by n00b
The other answers show how you properly use $http in an Asynchronous manner using promises or what is also called chaining, and that is the correct way of using $http. Trying to do that Synchronously as you have asked will block the Controller's cycle which is something you never want to do.
其他答案显示了如何使用承诺以异步方式正确使用 $http 或也称为链接,这是使用 $http 的正确方法。尝试按照您的要求同步执行此操作将阻止控制器的循环,这是您永远不想做的事情。
Still you can do the terrible thing of checking status of a promise in a loop. That can be done by the $$state
property of the promise which has a property named status
你仍然可以做在循环中检查承诺状态的可怕事情。这可以通过$$state
具有名为的属性的承诺的属性来完成status
回答by Patrick Evans
You can use the promise that is returned by $http method calls:
您可以使用 $http 方法调用返回的承诺:
//Do some request
$http.get("someurl")
//on resolve call processSomeUrlResponse
.then(processSomeUrlResponse)
//then do another request
.then(function(){
return $http.get("anotherurl").then(processAnotherUrlResponse);
})
//when previous request is resolved then do another
.then(function(){
return $http.get("yetanotherurl").then(processYetAnotherUrlResponse);
})
//and do another
.then(function(){
return $http.get("urls").then(processUrlResponse);
});
When you return a promise in a then
callback the next then
will not be called till the promise has been resolved.
当您在then
回调中返回承诺时,then
在承诺得到解决之前不会调用下一个。
回答by Sir Neuman
It is possible with angular http functions using promises. E.G:
使用 Promise 的 angular http 函数是可能的。例如:
$scope.functionA = function(){
return $q(function(resolve){
resolve("theAnswertoallquestions");
});
}
$scope.functionB = function(A){
return $q(function(resolve);
$http.get("URLRoot/" + A).success(function(){resolve();});
});
}
$scope.functionC = function(){
return $q(function(resolve);
resolve("I AM THE LAST TO EXEGGCUTE!!!");
});
}
$scope.allTogetherNow = function(){
var promise = $scope.functionA();
promise.then(function(A){
return $scope.functionB(A);
}).then(function(){
return $scope.functionC();
}).then(function(){
return "ALL DONE"
});
}
$scope.allTogetherNow();