2013-08-24 23 views
81

Tôi đang sử dụng một số dữ liệu 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 điều đó. Vì vậy, tôi bắt buộc phải lấy dữ liệu một lần từ máy chủ và mỗi khi tôi nhận được dữ liệu với dịch vụ được xác định đó. Giống như một biến toàn cầu. Dưới đây là các mẫu:

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

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

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

của nó làm việc 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 tôi, dịch vụ sẽ được gọi lại và yêu cầu máy chủ. Nếu ở giữa một số chức năng khác thực hiện mà phụ thuộc vào "dịch vụ được xác định", Nó cho lỗi như "cái gì đó" là không xác định. Vì vậy, tôi muốn chờ trong kịch bản của tôi cho đến khi dịch vụ được tải. Làm thế nào tôi có thể làm điều đó? Có anyway làm điều đó trong angularjs?

Trả lời

138

Bạn nên sử dụng 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 dự kiến ​​trong tương lai." (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise)

An thực hiện ví dụ sẽ là 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); 
    }); 
} 

Edit: Về Sujoys nhận xét rằng gì tôi cần phải làm như vậy mà myFuction() gọi sẽ không trở lại cho đến khi .Sau đó() chức năng kết thúc thực hiện.

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

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

Với lời hứa trở lại ngay lập tức, trình duyệt được tự do tiếp tục với mã khác trong thời gian chờ đợi. Khi lời hứa giải quyết/thất bại, cuộc gọi sau đó() đượ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 (phức tạp là vấn đề thường gặp của lập trình không đồng bộ/song song nói chung sau khi tất cả!)

+2

Điều này giải quyết được vấn đề của tôi !!! Đối với bất kỳ ai khác, tôi có một trình đơn thả xuống cần dữ liệu từ cuộc 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 gán để có dữ liệu đến từ cuộc gọi ajax. –

+6

@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 đó. Sau đó() sẽ gọi sau. Tôi cần phải làm gì để cuộc gọi myFuction() không trở lại cho đến khi hàm .then() kết thúc thực hiện. 'hàm myFunction ($ scope, myService) { var myDataPromise = myService.getData(); myDataPromise.then (hàm (kết quả) { $ scope.data = result; console.log ("data.name" + $ scope.data.name); }); console.log ("Điều này sẽ được in trước data.name bên trong sau đó. Và tôi không muốn điều đó."); } ' – Sujoy

12

cho những người mới này cũng có thể sử dụng một callback 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 điều khiển của bạn:

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

Giải pháp tuyệt vời. Đã suy nghĩ cùng dòng này khi tôi đang nhìn vào nó. Vui mừng một người nào đó đặt điều này ra khỏi đó. – Nate

0

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

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

    return { data: data } 
}); 

và sau đó là chức năng 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 phải là cần thiết nhưng tôi nghĩ rằng một thói quen tốt của nó đối với khả năng mở rộng . Hầu hết những gì bạn sẽ cần cho một sẽ cho bất kỳ 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.

0

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

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

và trong giao diện tôi chỉ

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

trong lần đầu tiên/xem mẹ yếu tố/wrapper để bộ điều khiển có thể chạy tất cả mọi thứ bên trong

myfunct() 

mà không lo lắng về những lời hứa async/trật tự/que vấn đề ue. Tôi hy vọng rằng sẽ giúp ai đó với cùng một vấn đề tôi đã có.

Các vấn đề liên quan