2016-07-08 22 views
5

Câu hỏi:Trình tự hứa trong AngularJS

Có một cách "dễ dàng" để hủy bỏ ($q -/$http -) hứa hẹn trong AngularJS hoặc xác định thứ tự trong đó hứa hẹn đã được giải quyết?

Ví dụ

Tôi có một tính toán lâu chạy và tôi yêu cầu kết quả qua $http. Một số hành động hoặc sự kiện yêu cầu tôi phải khởi động lại phép tính (và do đó gửi yêu cầu $http mới) trước khi lời hứa ban đầu được giải quyết. Do đó tôi tưởng tượng tôi không thể sử dụng thực hiện đơn giản như

$http.post().then(function(){ 
    //apply data to view 
}) 

vì tôi không thể đảm bảo rằng các câu trả lời trở lại theo thứ tự mà tôi đã gửi yêu cầu - sau tất cả tôi muốn hiển thị kết quả của tính toán mới nhất khi tất cả các lời hứa đã được giải quyết đúng cách.

Tuy nhiên tôi muốn tránh chờ đợi câu trả lời đầu tiên cho đến khi tôi gửi một yêu cầu mới như thế này:

const timeExpensiveCalculation = function(){ 
    return $http.post().then(function(response){ 
     if (isNewCalculationChained) {return timeExpensiveCalculation();}    
     else {return response.data;} 
    }) 
} 

Suy nghĩ:

Khi sử dụng $http tôi có thể truy cập vào config- đối tượng trên phản hồi để sử dụng một số dấu thời gian hoặc các số nhận dạng khác để tự sắp xếp các câu trả lời đến. Tuy nhiên tôi đã hy vọng tôi chỉ có thể nói góc cạnh bằng cách nào đó để hủy bỏ một lời hứa đã lỗi thời và do đó không chạy hàm .then() khi nó được giải quyết.

Điều này không hoạt động nếu không có triển khai thủ công cho $q -promises thay vì $http.

Có lẽ chỉ từ chối lời hứa ngay là con đường để đi? Nhưng trong cả hai trường hợp nó có thể mất mãi mãi cho đến khi cuối cùng một lời hứa được giải quyết trước khi yêu cầu tiếp theo được tạo ra (dẫn đến một cái nhìn trống trong thời gian chờ đợi).

Có một số chức năng API góc mà tôi đang thiếu hoặc có các mẫu thiết kế mạnh mẽ hoặc "thủ thuật" với chuỗi lời hứa hoặc $ q.all để xử lý nhiều lời hứa trả lại dữ liệu "giống nhau" không?

+0

Không chắc chắn bạn đang sử dụng API nào nhưng trong api .Net của tôi, tôi đã sử dụng SignalR để xử lý các tình huống như thế này. – jbrown

+1

Câu hỏi hay, mong được trả lời. Nhưng nó sẽ không dễ dàng hơn để xử lý logic bên trong .then thay vì cố gắng tránh lời hứa được giải quyết? – user2263572

+0

Có thể trùng lặp [Hứa hẹn - có thể buộc hủy lời hứa] (http://stackoverflow.com/questions/30233302/promise-is-it-possible-to-force-cancel-a-promise) –

Trả lời

3

tôi làm điều đó bằng cách tạo ra một requestId, và chức năng của lời hứa then() tôi kiểm tra xem câu trả lời đến từ gần đây nhất requestId.

Mặc dù cách tiếp cận này không thực sự hủy các lời hứa trước đó, nhưng nó cung cấp một cách nhanh chóng và dễ dàng để đảm bảo rằng bạn đang xử lý câu trả lời của yêu cầu gần đây nhất.

Cái gì như:

var activeRequest; 
function doRequest(params){ 
    // requestId is the id for the request being made in this function call 
    var requestId = angular.toJson(params); // I usually md5 hash this 

    // activeRequest will always be the last requestId sent out 
    activeRequest = requestId; 

    $http.get('/api/something', {data: params}) 
     .then(function(res){ 
      if(activeRequest == requestId){ 
       // this is the response for last request 

       // activeRequest is now handled, so clear it out 
       activeRequest = undefined; 
      } 
      else { 
       // response from previous request (typically gets ignored) 
      } 
     }); 
} 

Edit: Trên một lưu ý phụ, tôi muốn nói thêm rằng khái niệm này theo dõi requestId's cũng có thể được áp dụng để ngăn chặn yêu cầu trùng lặp. Ví dụ, trong phương pháp load(module, id)Data dịch vụ của tôi, tôi làm một quá trình ít như thế này:

  1. tạo ra requestId dựa trên các thông số URL +.
  2. kiểm tra trong các yêu cầu bảng băm cho requestId

    • nếu requestId không được tìm thấy: tạo yêu cầu mới và cửa hàng cam kết trong bảng băm
    • nếu requestId được tìm thấy: chỉ cần trả lại lời hứa từ băm -table
  3. Khi yêu cầu hoàn tất, hãy xóa mục nhập của requestId khỏi bảng băm.

+0

Cảm ơn rất nhiều! Tôi sẽ chấp nhận câu trả lời này vì nó thực sự đề cập đến angularJS đó là những gì tôi yêu cầu.Câu trả lời của Redu chứa một ví dụ làm việc cho kỹ thuật này (không sử dụng Angular) –

4

Hủy lời hứa chỉ làm cho nó không gọi hàm onFulfilledonRejected ở giai đoạn then. Vì vậy, như @ user2263572 đề cập đến nó luôn luôn tốt nhất để cho đi lời hứa không bị hủy bỏ (ES6 bản xứ hứa hẹn không thể được hủy bỏ anyways) và xử lý tình trạng này trong đó là then giai đoạn (như bỏ qua nhiệm vụ nếu một biến toàn cầu được đặt thành 2 như được hiển thị trong đoạn mã sau) và tôi chắc chắn bạn có thể tìm thấy rất nhiều cách khác để làm điều đó. Một ví dụ có thể là;

Rất tiếc, tôi sử dụng v (trông giống như ký tự kiểm tra) cho resolvex (hiển nhiên) cho các chức năng reject.

var prom1 = new Promise((v,x) => setTimeout(v.bind(null,"You shall not read this"),2000)), 
 
     prom2, 
 
validPromise = 1; 
 
prom1.then(val => validPromise === 1 && console.log(val)); 
 
// oh what have i done..!?! Now i have to fire a new promise 
 
prom2 = new Promise((v,x) => setTimeout(v.bind(null,"This is what you will see"),3000)); 
 
validPromise = 2; 
 
prom2.then(val => validPromise === 2 && console.log(val));

0

Tôi vẫn đang cố gắng tìm ra một cách tốt để đơn vị thử nghiệm này, nhưng bạn có thể thử loại này của chiến lược:

var canceller = $q.defer(); 
service.sendCalculationRequest = function() { 
    canceller.resolve(); 
    return $http({ 
     method: 'GET', 
     url: '/do-calculation', 
     timeout: canceller.promise 
    }); 
}; 
+0

Tôi tìm thấy điều này trong một chủ đề khác sau khi tôi đăng câu hỏi này. Điều này vẫn chỉ hoạt động cho các cuộc gọi '$ http'. –

+0

Ah tôi thấy, vì vậy bạn đang tìm kiếm thứ gì đó với '$ resource'. –

0

Trong lời hứa ECMA6, there is a Promise.race(promiseArray) method. Điều này có một loạt các lời hứa như là đối số của nó, và trả về một lời hứa duy nhất. Lời hứa đầu tiên để giải quyết trong mảng sẽ đưa giá trị đã giải quyết của nó đến số .then của lời hứa được trả lại, trong khi mảng khác hứa hẹn sẽ đến thứ hai, v.v., sẽ không được chờ đợi.

Ví dụ:

var httpCall1 = $http.get('/api/something', {data: params}) 
    .then(function(val) { 
     return { 
      id: "httpCall1" 
      val: val 
     } 
    }) 
var httpCall2 = $http.get('/api/something-else', {data: params}) 
    .then(function(val) { 
     return { 
      id: "httpCall2" 
      val: val 
     } 
    }) 
// Might want to make a reusable function out of the above two, if you use this in Production 
Promise.race([httpCall1, httpCall2]) 
    .then(function(winningPromise) { 
     console.log('And the winner is ' + winningPromise.id); 
     doSomethingWith(winningPromise.val); 
    }); 

Bạn có thể có thể sử dụng điều này với một polyfil Promise, hoặc look into the q.race that someone's developed for Angular (mặc dù tôi đã không kiểm tra nó).

+0

điều này có thể có một số ứng dụng rất hữu ích khác nhưng với phương pháp này tôi nhận được dữ liệu "ngẫu nhiên" (tùy thuộc vào thời gian lời hứa cần phải giải quyết) thay vì cập nhật nhất. Vì vậy, nó không trả lời câu hỏi trừ khi tôi đang thiếu một cái gì đó. –

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