.json()がPromiseを返すのはなぜですか?


115

私はfetch()最近、APIをいじり回していて、少し風変わりなことに気づきました。

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.dataPromiseオブジェクトを返します。 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));
;

postObjectこれは、title属性にアクセスできる標準です。 http://jsbin.com/wofulo/edit?js,output

だから私の質問は、なぜresponse.jsonオブジェクトリテラルでプロミスを返すのですか?


1
これはresponse.json()、応答が有効なJSONではない場合に、promiseが拒否される可能性があると考える場合に意味があります。
ssube

1
response.json()で値を渡すとpromiseが解決されたため、値が返されます。これで、thenメソッドで値を使用できるようになりました。
Jose Hermosilla Rodrigo

回答:


167

なぜresponse.json約束を返すのですか?

responseすべてのヘッダーが到着するとすぐにを受け取るからです。呼び出す.json()と、まだ読み込まれていないhttp応答の本文に対する別の約束が得られます。JavaScriptフェッチAPIからの応答オブジェクトが約束である理由も参照してください

thenハンドラーからpromiseを返すとなぜ値が取得されるのですか?

それが約束が機能する方法だからです。コールバックからプロミスを返し、プロミスを採用させる機能は、最も関連性の高い機能であり、ネストせずにチェーンできるようにします。

使用できます

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

または、以前のpromiseにアクセスするためのその他のアプローチでは、.then()チェーンが生成され、json本文を待った後に応答ステータスが取得されます。


Promiseを使用してデータが返されるのを待つだけではおかしく、到着したらjsonに変換しますか?または、おそらくその場合、JSON.parse()代わりに使用できますres.json()か?
ココドコ2017年

8
@Kokodokoはres.json()基本的にのショートカットですres.text().then(JSON.parse)。どちらもpromiseを使用してデータを待機し、jsonを解析します。
Bergi、

@Bergiさん、こんにちは、私は混乱に直面しました。つまり、then(res => res.json())を使用して、JSONを取得するための別のリクエストを送信しますか?
mirzhal

1
@mirzhalいいえ、他にリクエストはありません。残りの応答を(非同期で)読み取っているだけです。
Bergi、

14

この違いは、Promiseの動作によるfetch()ものです。

.then()コールバックが追加のを返す場合、チェーン内Promiseの次の.then()コールバックは基本的にそのPromiseにバインドされ、解決または拒否のフルフィルメントと値を受け取ります。

2番目のスニペットは次のように記述することもできます。

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

この形式とあなたの形式の両方で、の値はpostから返されるPromiseによって提供されresponse.json()ます。


Objectただし、plainを返す.then()と、は成功した結果と見なし、次のように自動的に解決します。

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

postこの場合は、単にObjectあなたが作成したものPromiseであり、dataプロパティにを保持しています。その約束が果たされるのを待つのはまだ不完全です。


7

また、あなたが説明したこの特定のシナリオを理解するのに役立ったのは、Promise API ドキュメントです。具体的には、thenメソッドによって返されるpromise がハンドラーfnが返すものに応じて異なる方法で解決される方法を説明しています。

ハンドラー関数の場合:

  • 値を返します。それまでに返されたpromiseは、返された値を値として解決されます。
  • エラーをスローし、それによって返されたpromiseは、スローされたエラーを値として拒否されます。
  • すでに解決されたpromiseを返します。それまでに返されたpromiseは、そのpromiseの値を値として解決されます。
  • すでに拒否されたpromiseを返します。それまでに返されたpromiseは、そのpromiseの値を値として拒否されます。
  • 別の保留中のpromiseオブジェクトを返します。それまでに返されたpromiseの解決/拒否は、ハンドラーによって返されたpromiseの解決/拒否に続きます。また、thenによって返されるpromiseの値は、ハンドラーによって返されるpromiseの値と同じになります。

5

上記の回答に加えて、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
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.