Cách gọi $ http Cuộc gọi đồng bộ với AngularJS


132

Có cách nào để thực hiện cuộc gọi đồng bộ với AngularJS không?

Tài liệu AngularJS không rõ ràng hoặc bao quát để tìm ra một số nội dung cơ bản.

TRÊN DỊCH VỤ:

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

Xem thêm nhóm.google.com/d/topic/angular/qagzXXhS_VI/discussion để biết một số ý tưởng về cách xử lý hành vi không đồng bộ: sự kiện, $ watch, tải trước ở phía máy chủ, sử dụng lời hứa được trả về từ $ http.
Mark Rajcok

1
Không đồng bộ luôn tốt hơn, đặc biệt là khi bạn có lời hứa.
Andrew Joslin

Nhiều lần, bạn có thể tránh các cuộc gọi đồng bộ. Xem cách $ resource hoạt động stackoverflow.com/questions/11966252/ .
honzajde

3
@AndrewJoslin Không đồng bộ tệ hơn khi bạn cần giao hàng theo yêu cầu.
Stijn Van Antwerppen

Câu trả lời:


113

Không phải hiện tại. Nếu bạn xem mã nguồn (từ thời điểm này vào thời điểm tháng 10 năm 2012) , bạn sẽ thấy rằng cuộc gọi đến XHR mở thực sự được mã hóa cứng để không đồng bộ (tham số thứ ba là đúng):

 xhr.open(method, url, true);

Bạn cần phải viết dịch vụ của riêng bạn đã thực hiện các cuộc gọi đồng bộ. Nói chung, đó không phải là điều bạn thường muốn làm vì bản chất của việc thực thi JavaScript, cuối cùng bạn sẽ chặn mọi thứ khác.

... nhưng .. nếu chặn mọi thứ khác thực sự mong muốn, có lẽ bạn nên xem xét lời hứa và dịch vụ $ q . Nó cho phép bạn đợi cho đến khi một tập hợp các hành động không đồng bộ được thực hiện, và sau đó thực hiện một cái gì đó sau khi hoàn tất. Tôi không biết trường hợp sử dụng của bạn là gì, nhưng điều đó có thể đáng xem.

Ngoài ra, nếu bạn sẽ tự mình thực hiện, có thêm thông tin về cách thực hiện các cuộc gọi ajax đồng bộ và không đồng bộ có thể được tìm thấy ở đây .

Tôi hi vọng điều đó hữu ích.


12
Bạn có thể vui lòng mã đoạn trích để đạt được bằng cách sử dụng dịch vụ $ q. Tôi đã thử nhiều tùy chọn nhưng nó hoạt động theo cách không đồng bộ.
Venkat

1
Có những nơi có thể có ý nghĩa, ví dụ như khi người dùng đóng trình duyệt (onb Beforeunload), nếu bạn muốn lưu, bạn phải gửi yêu cầu đồng bộ hóa, tùy chọn khác là hiển thị hủy hộp thoại, sau đó khởi chạy lại cửa sổ?
Braulio

2
@Venkat: Tôi biết đây là phản hồi muộn, nhưng như tôi đã nói trong câu trả lời, cuộc gọi sẽ luôn luôn "không đồng bộ", bạn chỉ cần sử dụng $ q để làm cho nó chờ phản hồi, sau đó tiếp tục logic của bạn bên trong .then(callback). đại loại như : doSomething(); $http.get('/a/thing').then(doEverythingElse);.
Ben Lesh

3
Video sau đây đã giúp tôi trong việc nghiên cứu những lời hứa AngularJS Promising với $ q
Ilya Palkin

1
@BenLesh Tôi không phải là không thích hợp với thời gian bạn đặt vào, hoặc thời gian bất cứ ai đưa vào. Tôi thoải mái bỏ phiếu cho câu trả lời của bạn và nói rằng nó sẽ hữu ích cho tôi nếu một ví dụ được cung cấp. Tôi thấy câu trả lời của bạn, nó không giúp tôi, vì vậy tôi đã bỏ phiếu và đóng tab, và quay lại google để cố gắng tìm câu trả lời hữu ích hơn cho tôi. Đó không phải là ngày tận thế khi ai đó bình chọn câu trả lời của bạn và cho bạn biết làm thế nào để cải thiện nó. Bạn có muốn tôi bỏ phiếu mà không để lại nhận xét như tại sao không? Chỉ cần thành thật.
mạch

12

Tôi đã làm việc với một nhà máy được tích hợp với google maps tự động hoàn thành và những lời hứa được thực hiện, tôi hy vọng bạn phục vụ.

http://jsfiddle.net/the_pianist2/vL9nkfe3/1/

bạn chỉ cần thay thế dịch vụ tự động hoàn thành theo yêu cầu này bằng $ http incuida trước khi xuất xưởng.

app.factory('Autocomplete', function($q, $http) {

và $ http yêu cầu với

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

});

câu hỏi được thực hiện trên:

deferred.resolve(varResult); 

khi bạn đã làm tốt và yêu cầu:

deferred.reject(error); 

khi có lỗi và sau đó:

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

Gần đây tôi đã gặp phải một tình huống mà tôi muốn thực hiện các cuộc gọi $ http được kích hoạt bởi một trang tải lại. Giải pháp tôi đã thực hiện:

  1. Đóng gói hai cuộc gọi thành các chức năng
  2. Truyền cuộc gọi $ http thứ hai dưới dạng gọi lại vào chức năng thứ hai
  3. Gọi hàm thứ hai trong apon .success

Điều gì xảy ra nếu đó là một vòng lặp for, với n lần gọi máy chủ.
mithun

2

Đây là cách bạn có thể thực hiện không đồng bộ và quản lý mọi thứ như bình thường. Mọi thứ vẫn được chia sẻ. Bạn nhận được một tham chiếu đến đối tượng mà bạn muốn cập nhật. Bất cứ khi nào bạn cập nhật điều đó trong dịch vụ của mình, nó sẽ được cập nhật trên toàn cầu mà không phải xem hoặc trả lại lời hứa. Điều này thực sự tốt vì bạn có thể cập nhật đối tượng cơ bản từ bên trong dịch vụ mà không cần phải rebind. Sử dụng Angular theo cách nó được sử dụng. Tôi nghĩ rằng đó có thể là một ý tưởng tồi để làm cho $ http.get / bài đăng đồng bộ. Bạn sẽ nhận được một độ trễ đáng chú ý trong kịch bản.

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

Và một nơi nào đó trong một khung nhìn:

<h1>{{settings.assessment.title}}</h1>

0

XHR đồng bộ đang bị phản đối, tốt nhất không nên dựa vào điều đó. Nếu bạn cần thực hiện một yêu cầu POST đồng bộ hóa, bạn có thể sử dụng các trợ giúp sau bên trong dịch vụ để mô phỏng bài đăng mẫu.

Nó hoạt động bằng cách tạo một biểu mẫu với các đầu vào ẩn được đăng lên URL được chỉ định.

//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();
}

Sửa đổi theo yêu cầu cho nhu cầu của bạn.


-4

Điều gì về việc gói cuộc gọi của bạn trong một Promise.all()phương thức tức là

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

Theo MDN

Promise.all chờ đợi tất cả các thực hiện (hoặc từ chối đầu tiên)


bạn đang nói về cái gì vậy câu hỏi không liên quan gì đến nhiều lời hứa ...
Ovidiu Dolha

Nó sẽ chờ đợi một hoặc nhiều lời hứa để hoàn thành!
Manjit Dosanjh

bạn đã sử dụng nó để xem làm thế nào nó hoạt động? Promise.all sẽ trả lại một lời hứa khác, nó không chuyển đổi không đồng bộ thành các cuộc gọi đồng bộ hóa
Ovidiu Dolha

Hmm ... có vẻ như tài liệu MDN có thể mơ hồ ... Nó không thực sự WAIT như được nêu trong tài liệu của họ.
Manjit Dosanjh

Chào mừng đến với SO. Xin vui lòng đọc hướng dẫn cách trả lời này để cung cấp câu trả lời chất lượng.
thewaywewere
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.