2016-05-31 36 views
28

最近我一直在搞fetch()api,並且發現了一些有點古怪的東西。爲什麼.json()在對象文字中返回承諾?

let url = "http://jsonplaceholder.typicode.com/posts/6"; 

let iterator = fetch(url); 

iterator 
    .then(response => { 
     return { 
      data: response.json(), 
      status: response.status 
     } 
    }) 
    .then(post => document.write(post.data)); 
; 

post.data返回一個promise對象。 http://jsbin.com/wofulo/2/edit?js,output

但是如果寫成:這裏

let url = "http://jsonplaceholder.typicode.com/posts/6"; 

let iterator = fetch(url); 

iterator 
    .then(response => response.json()) 
    .then(post => document.write(post.title)); 
; 

後是可以訪問的標題屬性的標準對象。 http://jsbin.com/wofulo/edit?js,output

所以我的問題是:爲什麼response.json在對象字面量中返回承諾,但返回值如果剛返回?

+0

如果響應不是有效的JSON,可能會拒絕'response.json()'承諾,這是有意義的。 – ssube

+0

該值返回,因爲promise已經解決了在response.json()中傳遞值。現在該方法中的值可用。 –

回答

40

爲什麼response.json返回承諾?

因爲當所有標題都到達時您收到response。調用.json()可以讓您對尚未加載的http響應正文做出承諾。另請參閱Why the response object from JavaScript fetch API is a promise?

如果我從then處理程序返回承諾,爲什麼我會得到該值?

因爲that's how promises work。從回調中返回承諾並使它們被採用的能力是它們最相關的特性,它使得它們可以鏈接而不會嵌套。

您可以使用

fetch(url).then(response => 
    response.json().then(data => ({ 
     data: data, 
     status: response.status 
    }) 
).then(res => { 
    console.log(res.status, res.data.title) 
}); 

或任何其他approaches to access previous promise results in a .then() chain具有期待已久的JSON身體後能得到響應狀態。

+0

這似乎很奇怪,我不能等待數據使用Promise返回,並且當它到達時將其轉換爲json?或者在這種情況下,我可以使用'JSON.parse()'而不是'res.json()'? – Kokodoko

+1

@Kokodoko'res.json()'基本上是'res.text()。then(JSON.parse)'的快捷方式。都使用承諾等待數據並解析json。 – Bergi

9

這個差異是由於Promise的行爲超過fetch()而引起的。

.then()回調返回附加Promise時,鏈中的下一個.then()回調基本上綁定到該Promise,接收其解析或拒絕履行和價值。

iterator.then(response => 
    response.json().then(post => document.write(post.title)) 
); 

在這兩個這種形式,也是你提供的post值由無極從response.json()返回:

第2段可以爲也已被寫入。


當你回到一個普通的Object,雖然.then()認爲,一個成功的結果,並立即自行解決,類似於:

iterator.then(response => 
    Promise.resolve({ 
     data: response.json(), 
     status: response.status 
    }) 
    .then(post => document.write(post.data)) 
); 

post在這種情況下,僅僅是Object創建,其持有其data財產Promise。等待承諾的履行仍然不完整。

2

這裏除了上述的答案是你接受JSON編碼的錯誤消息,您會如何處理從API 500系列的迴應:

function callApi(url) { 
    return fetch(url) 
    .then(response => { 
     if (response.ok) { 
     return response.json().then(response => ({ response })); 
     } 

     return response.json().then(error => ({ error })); 
    }) 
    ; 
} 

let url = 'http://jsonplaceholder.typicode.com/posts/6'; 

const { response, error } = callApi(url); 
if (response) { 
    // handle json decoded response 
} else { 
    // handle json decoded 500 series response 
} 
0

還等什麼幫助我理解這個特殊的場景,你描述的是無極API documentation,具體在哪裏,它說明了如何承諾的由then方法返回會不同,這取決於解決什麼處理器FN回報:

如果處理函數:

  • 返回一個值,那麼返回的promise將被返回的值解析爲其值;
  • 拋出一個錯誤,那麼返回的promise將被拋出的錯誤作爲它的值拒絕;
  • 返回一個已經解決的承諾,那麼返回的承諾將以該承諾的值作爲其值解析;
  • 返回一個已經被拒絕的承諾,那麼返回的承諾將被拒絕,承諾的值將作爲其值。
  • 返回另一個掛起的承諾對象,解析/拒絕由此返回的承諾將在 解析/拒絕處理程序返回的承諾之後。此外,由此返回的承諾的 值將與處理程序返回的承諾的值 相同。