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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 12:39:35  来源:igfitidea点击:

How to make synchronous AJAX requests in AngularJS controller

javascriptjqueryajaxangularjsangular-promise

提问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 $qand 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:

另见:

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.

这并不意味着调用是同步的,但它们是异步的,并且仍然以更有效且易于管理的方式执行您需要的操作。

Demo

演示

回答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 $$stateproperty 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 thencallback the next thenwill not be called till the promise has been resolved.

当您在then回调中返回承诺时,then在承诺得到解决之前不会调用下一个。

Angular's $q(deferred/promise) service

Angular 的 $q(deferred/promise) 服务

回答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();