2012-12-02 36 views
83

Tôi đang cố gắng học AngularJS. Nỗ lực đầu tiên của tôi để nhận dữ liệu mới sau mỗi giây làm việc:Cuộc thăm dò của máy chủ với AngularJS

'use strict'; 

function dataCtrl($scope, $http, $timeout) { 
    $scope.data = []; 

    (function tick() { 
     $http.get('api/changingData').success(function (data) { 
      $scope.data = data; 
      $timeout(tick, 1000); 
     }); 
    })(); 
}; 

Khi tôi mô phỏng máy chủ chậm bằng cách chờ chuỗi trong 5 giây, nó chờ phản hồi trước khi cập nhật giao diện người dùng và đặt thời gian chờ khác. Vấn đề là khi tôi viết lại ở trên để sử dụng mô-đun góc và DI để tạo mô-đun:

'use strict'; 

angular.module('datacat', ['dataServices']); 

angular.module('dataServices', ['ngResource']). 
    factory('Data', function ($resource) { 
     return $resource('api/changingData', {}, { 
      query: { method: 'GET', params: {}, isArray: true } 
     }); 
    }); 

function dataCtrl($scope, $timeout, Data) { 
    $scope.data = []; 

    (function tick() { 
     $scope.data = Data.query(); 
     $timeout(tick, 1000); 
    })(); 
}; 

Điều này chỉ hoạt động nếu phản hồi của máy chủ nhanh. Nếu có bất kỳ sự chậm trễ nào, nó sẽ gửi đi 1 yêu cầu một giây mà không phải chờ phản hồi và dường như xóa giao diện người dùng. Tôi nghĩ rằng tôi cần phải sử dụng một chức năng gọi lại. Tôi cố gắng:

var x = Data.get({}, function() { }); 

nhưng có một lỗi: "Lỗi: destination.push không phải là một chức năng" này được dựa trên các tài liệu cho $resource nhưng tôi không thực sự hiểu những ví dụ đó.

Làm cách nào để phương pháp tiếp cận thứ hai hoạt động?

Trả lời

112

Bạn nên gọi hàm tick trong gọi lại cho query.

function dataCtrl($scope, $timeout, Data) { 
    $scope.data = []; 

    (function tick() { 
     $scope.data = Data.query(function(){ 
      $timeout(tick, 1000); 
     }); 
    })(); 
}; 
+3

Tuyệt vời, cảm ơn. Tôi không biết bạn có thể gọi lại ở đó. Điều đó giải quyết được vấn đề spam. Tôi cũng đã chuyển bài tập dữ liệu vào bên trong cuộc gọi lại đã giải quyết vấn đề thanh toán bù trừ UI. – David

+1

Rất vui được giúp đỡ! Nếu điều này giải quyết được vấn đề, bạn có thể chấp nhận câu trả lời này để câu trả lời khác sau này cũng có thể được hưởng lợi từ nó. – abhaga

+1

Giả sử mã trên là dành cho pageA và controllerA. Làm thế nào để tôi ngừng bộ đếm thời gian này khi tôi điều hướng đến pageB và controllerB? –

32

Phiên bản gần đây của góc đã giới thiệu $interval hoạt động tốt hơn $timeout để kiểm tra máy chủ.

var refreshData = function() { 
    // Assign to scope within callback to avoid data flickering on screen 
    Data.query({ someField: $scope.fieldValue }, function(dataElements){ 
     $scope.data = dataElements; 
    }); 
}; 

var promise = $interval(refreshData, 1000); 

// Cancel interval on page changes 
$scope.$on('$destroy', function(){ 
    if (angular.isDefined(promise)) { 
     $interval.cancel(promise); 
     promise = undefined; 
    } 
}); 
+13

-1, tôi không nghĩ rằng khoảng thời gian $ là phù hợp, bởi vì bạn không thể chờ phản hồi của máy chủ trước khi gửi yêu cầu tiếp theo. Điều này có thể dẫn đến nhiều yêu cầu khi máy chủ có độ trễ cao. – Treur

+4

@Treur: Trong khi đó dường như là sự khôn ngoan thông thường những ngày này, tôi không chắc chắn tôi đồng ý. Trong hầu hết các trường hợp, tôi muốn có một giải pháp linh hoạt hơn. Hãy xem xét trường hợp người dùng tạm thời ngoại tuyến hoặc cực đoan trong trường hợp máy chủ không phản hồi một yêu cầu duy nhất. Giao diện người dùng sẽ ngừng cập nhật đối với người dùng hết $ timeout vì thời gian chờ mới sẽ không được đặt. Đối với người dùng của khoảng thời gian $, giao diện người dùng sẽ chọn nơi nó đã dừng lại ngay sau khi kết nối được khôi phục. Rõ ràng chọn sự chậm trễ của sane cũng quan trọng. – Bob

+2

Tôi nghĩ nó thuận tiện hơn, nhưng không kiên cường. (Một nhà vệ sinh trong phòng ngủ của tôi cũng rất thuận tiện vào ban đêm, nhưng cuối cùng nó sẽ bắt đầu ngửi xấu;)) Khi lấy dữ liệu thực tế bằng cách sử dụng khoảng $ bạn bỏ qua kết quả máy chủ. Điều này thiếu một phương thức để thông báo cho người dùng của bạn, tạo điều kiện cho toàn vẹn dữ liệu hoặc ngắn gọn: quản lý trạng thái ứng dụng của bạn nói chung. Tuy nhiên, bạn có thể sử dụng các trình chặn $ http chung cho việc này và hủy bỏ khoảng thời gian $ khi điều này xảy ra. – Treur

1

Đây là phiên bản của tôi bằng cách sử dụng tính năng thăm dò đệ quy. Có nghĩa là nó sẽ chờ phản hồi của máy chủ trước khi bắt đầu thời gian chờ tiếp theo. Ngoài ra, khi xảy ra lỗi, nó sẽ tiếp tục bỏ phiếu nhưng trong một trang viên thoải mái hơn và theo thời gian của lỗi.

Demo is here

Written more about it in here

var app = angular.module('plunker', ['ngAnimate']); 

app.controller('MainCtrl', function($scope, $http, $timeout) { 

    var loadTime = 1000, //Load the data every second 
     errorCount = 0, //Counter for the server errors 
     loadPromise; //Pointer to the promise created by the Angular $timout service 

    var getData = function() { 
     $http.get('http://httpbin.org/delay/1?now=' + Date.now()) 

     .then(function(res) { 
      $scope.data = res.data.args; 

       errorCount = 0; 
       nextLoad(); 
     }) 

     .catch(function(res) { 
      $scope.data = 'Server error'; 
      nextLoad(++errorCount * 2 * loadTime); 
     }); 
    }; 

    var cancelNextLoad = function() { 
     $timeout.cancel(loadPromise); 
    }; 

    var nextLoad = function(mill) { 
     mill = mill || loadTime; 

     //Always make sure the last timeout is cleared before starting a new one 
     cancelNextLoad(); 
     $timeout(getData, mill); 
    }; 


    //Start polling the data from the server 
    getData(); 


     //Always clear the timeout when the view is destroyed, otherwise it will keep polling 
     $scope.$on('$destroy', function() { 
      cancelNextLoad(); 
     }); 

     $scope.data = 'Loading...'; 
    }); 
0

Chúng ta có thể làm điều đó một cách dễ dàng bỏ phiếu sử dụng $ khoảng dịch vụ. đây là tài liệu chi tiết về $ khoảng
https://docs.angularjs.org/api/ng/service/$interval
Vấn đề sử dụng $ khoảng được rằng nếu bạn đang làm nghĩa vụ $ http gọi điện thoại hoặc tương tác máy chủ và nếu trì hoãn hơn $ khoảng thời gian sau đó trước khi một yêu cầu của bạn hoàn tất, nó bắt đầu một yêu cầu khác.
Giải pháp:
1. Polling nên tình trạng đơn giản nhận được từ máy chủ giống như một chút đơn hoặc json nhẹ vì vậy không nên mất nhiều thời gian sau đó khoảng thời gian xác định của bạn. Bạn cũng nên xác định khoảng thời gian thích hợp để tránh vấn đề này.
2. Bằng cách nào đó nó vẫn đang xảy ra vì bất kỳ lý do gì, bạn nên kiểm tra cờ toàn cầu rằng yêu cầu trước đó đã hoàn thành hay không trước khi gửi bất kỳ yêu cầu nào khác. Nó sẽ bỏ lỡ khoảng thời gian đó nhưng nó sẽ không gửi yêu cầu sớm.
Ngoài ra nếu bạn muốn đặt giá trị ngưỡng sau khi đặt giá trị nào đó, bạn nên đặt theo cách sau.
Đây là ví dụ hoạt động.giải thích chi tiết here

angular.module('myApp.view2', ['ngRoute']) 
.controller('View2Ctrl', ['$scope', '$timeout', '$interval', '$http', function ($scope, $timeout, $interval, $http) { 
    $scope.title = "Test Title"; 

    $scope.data = []; 

    var hasvaluereturnd = true; // Flag to check 
    var thresholdvalue = 20; // interval threshold value 

    function poll(interval, callback) { 
     return $interval(function() { 
      if (hasvaluereturnd) { //check flag before start new call 
       callback(hasvaluereturnd); 
      } 
      thresholdvalue = thresholdvalue - 1; //Decrease threshold value 
      if (thresholdvalue == 0) { 
       $scope.stopPoll(); // Stop $interval if it reaches to threshold 
      } 
     }, interval) 
    } 

    var pollpromise = poll(1000, function() { 
     hasvaluereturnd = false; 
     //$timeout(function() { // You can test scenario where server takes more time then interval 
     $http.get('http://httpbin.org/get?timeoutKey=timeoutValue').then(
      function (data) { 
       hasvaluereturnd = true; // set Flag to true to start new call 
       $scope.data = data; 

      }, 
      function (e) { 
       hasvaluereturnd = true; // set Flag to true to start new call 
       //You can set false also as per your requirement in case of error 
      } 
     ); 
     //}, 2000); 
    }); 

    // stop interval. 
    $scope.stopPoll = function() { 
     $interval.cancel(pollpromise); 
     thresholdvalue = 0;  //reset all flags. 
     hasvaluereturnd = true; 
    } 
}]); 
Các vấn đề liên quan