AngularJS $http.get асинхронный порядок выполнения

Недавно я много кодил в AngularJS. Через некоторое время он начал чувствовать себя комфортно с ним, а также стал действительно продуктивным. Но, к сожалению, я не понимаю одного:

В моем проекте мне нужно получать данные через $http.get и сервер RESTful API. Вот тут я начал спотыкаться в первую очередь. После реализации обещания ($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
};

Я не могу понять, в каком порядке выполняются команды. Поскольку я использую IDE Webstorm и его функцию отладки, было бы точнее сказать, что я не знаю, почему команды выполняются в непонятном мне порядке.

Проще говоря, все, что включено в forEach, должно быть выполнено до достижения возврата, потому что $http.get подключены через .then. Но следуя отладочной информации, функция перебирает locationCount++ и даже возвращает промис до того, как углубится (имеется в виду после первого .then() ).

Что это такое? Я неправильно понял эту часть концепции AngularJS?

Или это просто очень плохая практика, и я должен найти другое решение?

Если контекст важен/интересен: объекты основаны на, например, https://www.hl7.org/fhir/2015May/location.html#5.15.3


person J.S.    schedule 09.07.2015    source источник
comment
Однако все они должны запускаться одновременно, поскольку это асинхронно, и нет гарантии, в каком порядке они завершатся.   -  person Kevin B    schedule 09.07.2015
comment
Хорошо, я это понимаю. Но разве нет способа контролировать поведение или, по крайней мере, позволить функции ждать? Я думал, что .then() (включая обещание) синхронизирует $http.get!?   -  person J.S.    schedule 09.07.2015
comment
Неа. невозможно, если только вы не хотите запускать их последовательно, что будет НАМНОГО медленнее. Тем не менее, есть способы подождать, пока все они будут завершены, а затем обработать ответы в том порядке, в котором они были отправлены.   -  person Kevin B    schedule 09.07.2015


Ответы (2)


С помощью JavaScript вы можете создавать только однопоточные приложения, хотя, например. здесь говорят, что это не гарантируется.

Но мы говорим о реальном мире и реальных браузерах, поэтому ваш пример кода выполняется как один поток (кстати, этот же поток также используется для рендеринга вашего CSS и HTML, по крайней мере, в Firefox).

Когда дело доходит до асинхронного вызова

$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 печатается перед 2, потому что задача не выполняется до тех пор, пока не будет напечатано 3.

person smnbbrv    schedule 09.07.2015

$http.get является асинхронным, поэтому в зависимости (среди прочего) от размера извлеченных данных время, необходимое для «завершения» получения, является переменным. Поэтому нельзя сказать, в каком порядке они будут завершены.

person Guinn    schedule 09.07.2015