AngularJS $http.get异步执行顺序

6

最近我在使用AngularJS进行大量编码。经过一段时间的使用,我开始感到舒适并且变得非常高效。但不幸的是,有一件事情我不理解:

在我的项目中,我需要通过$http.get和RESTful API服务器获取数据。这是我第一次遇到问题。在对处理必要数据的函数实现promise ($q.defer等和.then)后,我以为已经解决了问题。

但在这段代码中:

$scope.getObservationsByLocations = function() {
        var promise = $q.defer();
        var locationCount = 0;

        angular.forEach($scope.analysisData, function(loc) {   // for each location
            $http.get($scope.api + 'Device?_format=json', {     // get all devices
                params: {
                    location: loc.location.id
                }
            }).then(function (resultDevices) {
                var data = angular.fromJson(resultDevices);
                promise.resolve(data);
                // for each device in this location
                angular.forEach(angular.fromJson(resultDevices).data.entry.map(function (dev) {
                    http.get($scope.api + 'Observation?_format=json', {     // get all observations
                        params: {
                            device: dev.resource.id
                        }
                    }).then(function (resultObservations) {
                        var observations = angular.fromJson(resultObservations);
                        // for each obervation of that device in this location
                        angular.forEach(observations.data.entry.map(function(obs) {
                            $scope.analysisData[locationCount].observations.push({observation: obs.resource});
                        }));

                    })
                }))
            });
            locationCount++
        });
        return promise.promise
};

我无法理解命令的执行顺序。由于我使用Webstorm IDE及其调试功能,更准确地说,我不知道为什么命令以我不理解的顺序执行。
简单思考,forEach中包含的所有内容都必须在到达return之前执行,因为$http.get通过.then连接。但是根据调试信息,该函数遍历locationCount++,甚至在进入更深层次之前(即第一个.then()之后)就返回了promise。
这是怎么回事?我是否误解了AngularJS概念的这一部分?
还是这只是非常糟糕的做法,我应该寻求其他解决方案?
如果上下文很重要/有趣:对象基于例如https://www.hl7.org/fhir/2015May/location.html#5.15.3的内容。

它们应该同时开始,但由于是异步的,无法保证它们完成的顺序。 - Kevin B
好的,我理解了。但是有没有一种方法可以控制行为或者至少让函数等待呢?我以为.then()(以及它包含的promise)会同步$http.get!? - J.S.
不行,除非你想一个接一个地运行它们,但这样会慢得多。不过有办法可以等待它们全部完成,然后按照发送的顺序处理响应。 - Kevin B
2个回答

2

使用JavaScript,您只能创建单线程应用程序,尽管例如这里他们说它不保证是这样的。

但我们谈论的是现实世界和真实的浏览器,因此您的代码示例正在作为单个线程运行(顺便说一句,在Firefox中,相同的线程也用于呈现您的CSS和HTML)。

当涉及异步调用时

$http.get($scope.api + 'Device?_format=json', { 

这段话的意思是“嘿,我可以稍后做这件事”,但它会等待当前线程继续执行。

然后,一旦当前任务完成并使用return返回,它最终可以开始获取远程数据。

证明?请查看此演示

console.log(1);

for (var i=0;i<1000000;i++) setTimeout(function(){
    console.log(2);
},0);

console.log(3);

你看到了使用 for 循环的峰值吗?这是它注册了 setTimeout 异步调用的时刻。但是,由于任务在打印 3 之前并没有完成,所以 3 会在 2 之前被打印出来。

1
$http.get是异步的,因此取决于(除其他因素外)获取的数据大小,完成获取所需的时间是可变的。因此,无法确定它们将以何种顺序完成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接