2016-05-30 207 views
7

我需要將response.data取出承諾,以便可以通過封閉函數返回。我知道我可能無法按照我編寫它的方式進行編寫,因爲它的JavaScript範圍正常。有什麼辦法可以做到嗎?如何從承諾中返回數據

#1處的console.log會生成正確的數據。 console.log#2總是產生'a';

function addSiteParentId(nodeId) { 
    var theParentId = 'a'; 
    var parentId = relationsManagerResource.GetParentId(nodeId) 
         .then(function(response){        
          theParentId = response.data; 
          console.log(theParentId); // #1 
         }); 
    console.log(theParentId); // #2 
    return theParentId; 
} 

任何指針,將不勝感激。

+0

你費心尋找現有的關於這個問題嗎? – Amit

+1

否 - 你不能 - 你想用'response'完成的操作必須放在'.then()'處理程序中。您不能在同步樣式中編寫異步JavaScript! – slugonamission

+1

這不是關於從承諾中返回數據。 第二個'console.log'發生在承諾設置'theParentId'變量之前 - 因爲承諾是異步而'console.log'不是。 – JordanHendrix

回答

7

承諾背後的基本原則之一是它是異步處理的。這意味着您不能創建承諾,然後立即在代碼中同步使用其結果(例如,不可能從啓動承諾的函數內返回承諾的結果)。

你可能想要做的是返回整個承諾本身。然後,無論需要什麼樣的功能,其結果都可以在承諾上打電話.then(),當承諾解決後,結果將在那裏。

這裏是一個的HTML5Rocks的資源,越過一個承諾的生命週期,以及如何將其輸出異步解決:
http://www.html5rocks.com/en/tutorials/es6/promises/

+1

非常感謝您的溫柔指導。我知道這與我接觸它的方式有關。我對Angular很陌生,因此碰到了一堵磚牆。它現在正在工作,但恐慌結束後可能會進一步完善。再次感謝你提供的建議。 – Craig

0

你必須返回一個承諾,而不是一個變量。 所以在你的功能只是返回:

return relationsManagerResource.GetParentId(nodeId) 

而後解決返回的承諾。 或者您可以使其他人推遲並使用它解析theParentId

1

我也不喜歡使用一個函數來處理一個已經在每個控制器和服務中一次又一次解決的屬性。看來我並不孤單:D

不要試圖得到一個承諾作爲一個變量的結果,ofcourse沒辦法。但是我發現並使用了下面的解決方案來訪問作爲屬性的結果。

首先,結果寫入到您的服務的屬性:

app.factory('your_factory',function(){ 
    var theParentIdResult = null; 
    var factoryReturn = { 
      theParentId: theParentIdResult, 
      addSiteParentId : addSiteParentId 
    } 
    return factoryReturn; 
    function addSiteParentId(nodeId) { 
     var theParentId = 'a'; 
     var parentId = relationsManagerResource.GetParentId(nodeId) 
        .then(function(response){        
         factoryReturn.theParentIdResult = response.data; 
         console.log(theParentId); // #1 
      });      
    }   
}) 

現在,我們只需要確保方法addSiteParentId之前,我們訪問的財產theParentId總是可以解決。我們可以通過一些方式來實現這一點。

  • 使用決心路由器方法:

    決心:{ parentId的:函數(your_factory){ your_factory.addSiteParentId(); }}

然後在控制器和你的路由器使用的其他服務,只需撥打your_factory.theParentId讓你的財產。 Referce這裏瞭解更多信息: http://odetocode.com/blogs/scott/archive/2014/05/20/using-resolve-in-angularjs-routes.aspx

  • 使用「運行」應用程序的方法來解決你的服務。

    app.run(函數(your_factory){your_factory.addSiteParentId();})

  • 注入它在所述控制器的第一控制器或服務。在控制器中,我們可以調用所有需要的init服務。然後,所有作爲主控制器的子控制器的控制器都可以正常訪問該屬性。

選擇你的方式取決於你的上下文取決於你的變量的範圍和你的變量的閱讀頻率。對一個承諾返回數據

2

一種方法是這樣

const addSiteParentId = (nodeId) => { 
    const data = { theParentId: "" } 
    relationsManagerResource.GetParentId(nodeId).then((response)=> Object.assign(data, data.theParentId, response.data)/* #1 */); 
    return data.theParentId; 
} 
// Object.assign do this magic 
console.log("theParentId:", addSiteParentId(nodeId)) 

Object.assign:https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

+0

雖然這段代碼可能會回答這個問題,但提供關於爲什麼和/或代碼如何回答問題的其他內容可以提高其長期價值。 –

+0

謝謝@DonaldDuck –