AngularJS와 $ http를 동기화하는 방법


132

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;
}

비동기 동작을 처리하는 방법에 대한 아이디어 는 groups.google.com/d/topic/angular/qagzXXhS_VI/discussion참조 하십시오 . 이벤트, $ watch, 서버 측의 사전로드, $ http에서 반환 된 약속 사용.
Mark Rajcok

1
특히 약속이 있으면 비동기식이 항상 좋습니다.
앤드류 조슬린

많은 경우 동기 호출을 피할 수 있습니다. $ 자원의 작동 방식을 참조하십시오 stackoverflow.com/questions/11966252/...을 .
honzajde

3
주문 배달이 필요할 때 @AndrewJoslin 비동기가 더 나쁩니다.
Stijn Van Antwerpen

답변:


113

현재는 아닙니다. 소스 코드살펴보면 (이 시점부터 2012 년 10 월 시점) XHR 열기 호출이 실제로 비동기식으로 하드 코딩되어 있음을 알 수 있습니다 (세 번째 매개 변수는 true).

 xhr.open(method, url, true);

동기식 호출을 수행 한 고유 한 서비스를 작성해야합니다. 일반적으로 JavaScript 실행의 특성으로 인해 다른 모든 것을 차단하게됩니다.

...하지만 .. 다른 모든 것을 차단하는 것이 실제로 필요한 경우 약속과 $ q 서비스를 살펴보십시오 . 이를 통해 일련의 비동기 작업이 완료 될 때까지 기다렸다가 모두 완료되면 무언가를 실행할 수 있습니다. 유스 케이스가 무엇인지 모르지만 살펴볼 가치가 있습니다.

그 외에, 직접 롤링하려는 경우 동기식 및 비동기식 아약스 호출 방법에 대한 자세한 정보는 여기를 참조하십시오 .

도움이 되길 바랍니다.


12
$ q 서비스를 사용하여 코드 스 니펫을 작성해 주시겠습니까? 많은 옵션을 시도했지만 비동기 방식으로 작동합니다.
Venkat

1
예를 들어 사용자가 브라우저를 닫을 때 (onbeforeunload) 바로 이해할 수있는 장소가 있습니다. 저장하려면 동기화 요청을 보내야하는 또 다른 옵션은 대화 상자 취소를 표시 한 다음 창을 다시 시작하는 것입니까?
Braulio 2014 년

2
@ Venkat : 나는 이것이 늦은 답변이라는 것을 알고 있지만, 대답에서 말했듯이 전화는 항상 "비동기 적"일 것입니다 . 응답을 기다리기 위해 $ q를 사용해야 합니다. .then(callback). 같은 : doSomething(); $http.get('/a/thing').then(doEverythingElse);.
Ben Lesh

3
다음 비디오는 AngularJS가 $ q로 약속
Ilya Palkin

1
@ BenLesh 나는 당신이 넣은 시간이나 누군가가 넣는 시간에 대해 감사하지 않습니다. 나는 당신의 대답을 자유롭게 투표하고 예제가 제공된다면 그것이 도움이되었을 것이라고 자유롭게 말할 수 있습니다. 귀하의 답변을 보았는데 도움이되지 않았으므로 투표를해서 탭을 닫은 다음 Google로 돌아와서 더 도움이되는 답변을 찾으십시오. 누군가가 귀하의 답변을 다운 투표하고 개선 할 수있는 방법을 알려주는 것은 세상의 끝이 아닙니다. 이유에 대한 의견을 남기지 않고 내가 투표를 선호 했습니까? 솔직 해져
회로

12

Google지도 자동 완성 기능과 약속이있는 공장에서 일했습니다.

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;

5
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;
                };

4

최근에 페이지 새로 고침으로 인해 $ http 호출을하고 싶은 상황에 처했습니다. 내가 함께 해결 한 솔루션 :

  1. 두 호출을 함수로 캡슐화
  2. 두 번째 $ http 호출을 두 번째 함수에 콜백으로 전달
  3. apon .success에서 두 번째 함수를 호출하십시오.

n 회 호출 서버와 함께 for 루프 인 경우 어떻게됩니까?
mithun

2

다음은 비동기 적으로 수행하고 평소처럼 관리 할 수있는 방법입니다. 모든 것이 여전히 공유됩니다. 업데이트하려는 객체에 대한 참조를 얻습니다. 서비스에서 업데이트 할 때마다 약속을 보거나 반환하지 않고도 전 세계적으로 업데이트됩니다. 리 바인드하지 않고도 서비스 내에서 기본 객체를 업데이트 할 수 있기 때문에 정말 좋습니다. Angular를 사용하는 방식으로 사용하십시오. 아마도 $ 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>

0

이후 동기 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();
}

필요에 따라 수정하십시오.


-4

Promise.all()메소드 에서 호출을 감싸는 것은 어떻습니까?

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

MDN 에 따르면

Promise.all은 모든 이행 (또는 첫 번째 거부)을 기다립니다.


무슨 소리 야? 질문은 여러 약속과 아무 관련이 없습니다 ...
Ovidiu Dolha

하나 이상의 약속이 완료 될 때까지 기다립니다!
Manjit Dosanjh

작동 방식을 확인하기 위해 이것을 사용 했습니까? Promise.all은 또 다른 약속을 반환합니다. 비 동기화를 동기화 호출로 변환하지 않습니다.
Ovidiu Dolha

흠 ... MDN 문서가 모호한 것 같습니다 ... 실제로 문서에 명시된대로 WAIT하지 않습니다.
Manjit Dosanjh

SO에 오신 것을 환영합니다. 양질의 답변을 제공 하는 방법을 알아 보십시오 .
thewaywe는
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.