2015-09-13 24 views
15

我一直在念叨$ q和承諾了幾天,我似乎明白了吧...有點。我在實踐中遇到以下情況:

  1. 發出$ http請求,並檢查是否可以進行後續調用。
  2. 如果第一次調用失敗,返回「無數據」,如果成功,說通話可以進行,第二個電話是由,如果不是 - 「無數據」一次。如果第二次調用成功,則返回數據,否則返回「無數據」。它看起來像這樣(約,我簡化了總體思路,所以不用擔心小錯誤這裏):

     return $http.get (something) 
          .then(function(allowedAccess){ 
           if(allowedAccess){ 
            return $http.get (somethingElse) 
             .then(function(result){return {data:result} }, 
             function(error){return {data:"n0pe"} } 
            ) 
           } else { 
            return {data:"n0pe"} 
           } 
          }, 
          function(){ return {data:"n0pe"} }); 
    

有人告訴我在這裏使用$ Q。我真的不明白我會怎麼樣或爲什麼。 $ http調用已經是承諾。

如果有一種方法,使這種清潔的,我看不出來。剛剛完成重讀這post on the subject。本質上,我錯過了什麼/有沒有更好的方法來做到這一點?

編輯:也只是重新閱讀a tutorial on chaining promises - 它不處理在所有呼叫失敗。基本上這是作爲盡職調查。

編輯2:這是多一個精心製作的的理論,我問一下,節選自第一篇文章:

這雖然是一個簡單的例子。如果你的then()回調函數返回另一個promise,它就變得非常強大。在那種情況下,next()只會在承諾解析後執行。這種模式可用於串行HTTP請求,例如(其中一個請求依賴於前一個的結果):

這看起來這是談論鏈:

asyncFn1(1) 
    .then(function(data){return asyncFn2(data)}) 
    .then(function(data){return asyncFn3(data)}) 

所以,如果我理解正確的話a)。不適用於我,因爲我沒有第三個功能。 B)。將適用於我,如果我有三個功能,因爲當我運行的第一個$ HTTP請求中的if語句,只有if語句裏面做我返回另一個承諾。所以,從理論上講,如果我有三個異步函數進行鏈接,我需要將我的if語句放在promise中?

+0

http://stackoverflow.com/a/37175801/2518285 –

回答

13

承諾真的有助於使異步調用的代碼組成。換句話說,它們允許你以類似的方式編寫你的代碼,你將如何編寫一組同步的調用(使用鏈接.then),並且就好像它的同步代碼在try/catch塊中一樣.catch)。

所以,想象一下你的HTTP調用被阻塞 - 你的邏輯看起來像這樣:

var allowedAccess, data; 
try { 
    allowedAccess = $http.get(something); 

    if (allowedAccess){ 
    try{ 
     var result = $http.get(somethingElse); 
     data = {data: result}; 
    } catch(){ 
     data = {data: "n0pe"}; 
    } 
    } else { 
    data = {data: "n0pe"}; 
    } 
} catch(){ 
    data = {data: "n0pe"}; 
} 
return data; 

你可以把它簡化一下:

var allowedAccess, result; 
try { 
    allowedAccess = $http.get(something); 
    var result; 
    if (allowedAccess) { 
    result = $http.get(somethingElse); 
    } else { 
    throw; 
    } 
    data = {data: result}; 
} catch() { 
    data = {data: "n0pe"}; 
} 
return data; 

這將轉換爲async版本:

return $http 
      .get(something) 
      .then(function(allowedAccess){ 
      if (allowedAccess){ 
       return $http.get(somethingElse); 
      } else { 
       return $q.reject(); // this is the "throw;" from above 
      } 
      }) 
      .then(function(result){ 
      return {data: result}; 
      }) 
      .catch(function(){ 
      return {data: "n0pe"}; 
      }) 

至少,這是你可以申請的原因,當你編寫co de分支和異步調用。

我並不是說我提出的版本是最優的或者更短 - 這,然而,更幹,因爲一個錯誤處理。但是要意識到,當你做.then(success, error)它相當於try/catch而不是以前的異步操作 - 根據你的具體情況,這可能需要也可能不需要。

+0

非常感謝您的詳細解答,仍在處理中,將於明天再次接受您或Matt的明確回答。 – VSO

+0

我們在這裏用$ q.reject()拒絕了什麼?我熟悉在使用$ q.defer()創建的延遲上使用reject()。這裏只是拒絕第二個$ http.call?但是,如果陳述不是承諾是一個問題?我很可能只是想念一些東西。 – VSO

+0

@VSO,'$ q.reject'等同於同步世界中的'throw'。這是一個被拒絕的承諾,所以它最終會在'.catch'而不是下一個'.then' –

-2

$ Q將有助於減少通話的金字塔是這樣的:

async-call1.then(... 
    aysnc-call2.then(... 

本博客文章 - http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/ - 提供使多個HTTP請求的清潔方式。注意使用$ q的更簡潔的方法。如果你打到一個HTTP端點,使用你的方法就好了。我會說,你所擁有的也是好的; $ q在未來可能會有更大的靈活性。

博客文章描述了服務,同時使用$ q和代碼看起來更乾淨。

service('asyncService', function($http, $q) { 
    return { 
    loadDataFromUrls: function(urls) { 
     var deferred = $q.defer(); 
     var urlCalls = []; 
     angular.forEach(urls, function(url) { 
     urlCalls.push($http.get(url.url)); 
     }); 
     // they may, in fact, all be done, but this 
     // executes the callbacks in then, once they are 
     // completely finished. 
     $q.all(urlCalls) 
     .then(... 

我是一個有承諾的初學者,所以帶上一粒鹽吧。

+3

OP的問題顯然需要順序調用,因爲第二個調用取決於第一個調用的返回參數。 'q.all'在呼叫彼此獨立時起作用 –

+0

好點,@NewDev。謝謝。 – zedfoxus

7

這是我會怎樣編寫這類問題:然而

// returns a promise that resolves some endpoint if allowed 
function getDataWithAccess(allowed){ 
    return allowed ? $http.get(someEndpoint) : $q.reject(); 
} 

// do something with data 
function handleData(data){ 
    // do stuff with your data 
} 

// main chain 
$http.get(accessCredEndpoint) 
    .then(getDataWithAccess) 
    .then(handleData) 
    .catch(function(err){ 
     return { data: "n0pe" }; 
    }); 

是的,這是非常像新開發的答案,我想使提取功能整合到自己的塊點。這使得整體代碼更具可讀性。

+0

謝謝你的回覆,看起來我需要一些時間來消化它,會回來接受你的或新的開發者在睡眠後的回答。 – VSO