Làm thế nào để đợi cho đến khi phản hồi đến từ yêu cầu $ http, trong anglejs?


93

Tôi đang sử dụng một số dữ liệu từ một dịch vụ RESTful trong nhiều trang. Vì vậy, tôi đang sử dụng các nhà máy góc cạnh cho việc đó. Vì vậy, tôi yêu cầu lấy dữ liệu một lần từ máy chủ và mọi lúc tôi đều lấy dữ liệu bằng dịch vụ đã xác định đó. Cũng giống như một biến toàn cục. Đây là mẫu:

var myApp =  angular.module('myservices', []);

myApp.factory('myService', function($http) {
    $http({method:"GET", url:"/my/url"}).success(function(result){
        return result;
    });
});

Trong bộ điều khiển của tôi, tôi đang sử dụng dịch vụ này như:

function myFunction($scope, myService) {
    $scope.data = myService;
    console.log("data.name"+$scope.data.name);
}

Nó hoạt động tốt cho tôi theo yêu cầu của tôi. Nhưng vấn đề ở đây là, khi tôi tải lại trang web của mình, dịch vụ sẽ được gọi lại và yêu cầu máy chủ. Nếu ở giữa một số thực thi chức năng khác phụ thuộc vào "dịch vụ được xác định", thì nó sẽ gây ra lỗi như "cái gì đó" không được xác định. Vì vậy, tôi muốn đợi trong tập lệnh của mình cho đến khi dịch vụ được tải. Làm thế nào tôi có thể làm điều đó? Có cách nào làm điều đó trong anglejs không?

Câu trả lời:


150

Bạn nên sử dụng các lời hứa cho các hoạt động không đồng bộ mà bạn không biết khi nào nó sẽ được hoàn thành. Lời hứa "đại diện cho một hoạt động chưa hoàn thành, nhưng được mong đợi trong tương lai." ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise )

Một ví dụ triển khai sẽ như sau:

myApp.factory('myService', function($http) {

    var getData = function() {

        // Angular $http() and then() both return promises themselves 
        return $http({method:"GET", url:"/my/url"}).then(function(result){

            // What we return here is the data that will be accessible 
            // to us after the promise resolves
            return result.data;
        });
    };


    return { getData: getData };
});


function myFunction($scope, myService) {
    var myDataPromise = myService.getData();
    myDataPromise.then(function(result) {  

       // this is only run after getData() resolves
       $scope.data = result;
       console.log("data.name"+$scope.data.name);
    });
}

Chỉnh sửa: Về nhận xét của Sujoys rằng Tôi cần làm gì để cuộc gọi myFuction () sẽ không trở lại cho đến khi hàm .then () kết thúc thực thi.

function myFunction($scope, myService) { 
    var myDataPromise = myService.getData(); 
    myDataPromise.then(function(result) { 
         $scope.data = result; 
         console.log("data.name"+$scope.data.name); 
    }); 
    console.log("This will get printed before data.name inside then. And I don't want that."); 
 }

Giả sử lệnh gọi getData () mất 10 giây để hoàn thành. Nếu hàm không trả về bất kỳ thứ gì trong thời gian đó, nó sẽ trở thành mã đồng bộ bình thường và sẽ treo trình duyệt cho đến khi hoàn thành.

Tuy nhiên, với lời hứa sẽ trả lại ngay lập tức, trình duyệt có thể tiếp tục với mã khác trong thời gian chờ đợi. Khi lời hứa giải quyết được / không thành công, lệnh gọi then () được kích hoạt. Vì vậy, nó có ý nghĩa hơn theo cách này, ngay cả khi nó có thể làm cho dòng mã của bạn phức tạp hơn một chút (xét cho cùng thì sự phức tạp là một vấn đề phổ biến của lập trình không đồng bộ / song song!)


2
Điều này đã giải quyết vấn đề của tôi !!! Đối với bất kỳ ai khác, tôi có một menu thả xuống cần dữ liệu từ lệnh gọi ajax, vì vậy khi phạm vi được tạo, dữ liệu không có sẵn. Với sự trì hoãn này, phạm vi có thể được chỉ định để có dữ liệu đến từ lệnh gọi ajax.
Kat Lim Ruiz

8
@mikel: Tôi có một câu hỏi khác ở đây. Cuộc gọi myFuction () của bạn sẽ trở lại ngay lập tức nhưng lời hứa đó .then () sẽ gọi sau. Tôi cần làm gì để lệnh gọi myFuction () không trả về cho đến khi hàm .then () kết thúc quá trình thực thi. function myFunction($scope, myService) { var myDataPromise = myService.getData(); myDataPromise.then(function(result) { $scope.data = result; console.log("data.name"+$scope.data.name); }); console.log("This will get printed before data.name inside then. And I don't want that."); }
Sujoy

13

đối với những người mới làm quen với điều này, bạn cũng có thể sử dụng một lệnh gọi lại, ví dụ:

Trong dịch vụ của bạn:

.factory('DataHandler',function ($http){

   var GetRandomArtists = function(data, callback){
     $http.post(URL, data).success(function (response) {
         callback(response);
      });
   } 
})

Trong bộ điều khiển của bạn:

    DataHandler.GetRandomArtists(3, function(response){
      $scope.data.random_artists = response;
   });

Giải pháp tuyệt vời. Tôi đã suy nghĩ cùng dòng này khi tôi đang xem xét nó. Rất vui khi ai đó đưa ra điều này.
Nate

0

FYI, điều này đang sử dụng Angularfire nên nó có thể thay đổi một chút đối với một dịch vụ khác hoặc mục đích sử dụng khác nhưng sẽ giải quyết cùng một cách mà $ http có. Tôi đã gặp vấn đề tương tự giải pháp duy nhất phù hợp với tôi nhất là kết hợp tất cả các dịch vụ / nhà máy thành một lời hứa duy nhất trên phạm vi. Trên mỗi tuyến đường / chế độ xem cần các dịch vụ / v.v. này được tải, tôi đặt bất kỳ hàm nào yêu cầu dữ liệu được tải bên trong hàm bộ điều khiển, tức là myfunct () và app.js chính được chạy sau khi xác thực tôi đã đặt

myservice.$loaded().then(function() {$rootScope.myservice = myservice;});

và theo quan điểm tôi vừa làm

ng-if="myservice" ng-init="somevar=myfunct()"

trong phần tử / trình bao bọc đầu tiên / cha mẹ để bộ điều khiển có thể chạy mọi thứ bên trong

myfunct()

mà không phải lo lắng về các vấn đề hứa hẹn / đơn hàng / hàng đợi không đồng bộ. Tôi hy vọng điều đó sẽ giúp ai đó có cùng vấn đề với tôi.


0

Tôi đã gặp vấn đề tương tự và không có vấn đề nào nếu những điều này làm việc cho tôi. Đây là những gì đã hoạt động mặc dù ...

app.factory('myService', function($http) {
    var data = function (value) {
            return $http.get(value);
    }

    return { data: data }
});

và sau đó hàm sử dụng nó là ...

vm.search = function(value) {

        var recieved_data = myService.data(value);

        recieved_data.then(
            function(fulfillment){
                vm.tags = fulfillment.data;
            }, function(){
                console.log("Server did not send tag data.");
        });
    };

Dịch vụ này không cần thiết lắm nhưng tôi nghĩ đó là một phương pháp hay để có thể mở rộng. Hầu hết những gì bạn cần cho một cái này sẽ cho bất kỳ cái nào khác, đặc biệt là khi sử dụng API. Dù sao tôi hy vọng điều này là hữu ích.

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.