web-dev-qa-db-ja.com

フェッチ:フェッチ応答で変数を設定し、関数から戻ります

私はJavaScriptにかなり慣れており、反応します。 idが指定されたサーバーからcustomer_nameを取得するコンポーネントからのコールバックがあります。フェッチは機能し、console.logはフルネームを正しく出力しますが、最後の.thenのcustomer_nameは設定されず、関数は空の文字列を返します。何故ですか?

// Gets the fullname of the customer from an id.
tj_customer_name(id) {
  let customer_name = '';

 fetch(`/customers/${id}.json`, {
   headers: API_HEADERS,
   credentials: 'same-Origin'
 })
 .then((response) => {
   if(response.ok) {
     return response.json();
   } else {
     throw new Error('Server response wasn\'t OK');
   }
 })
 .then((json) => {
   customer_name = json.first_name.concat(' ').concat(json.last_name);
   console.log(customer_name);
 });
 return customer_name;
}
8
k3rn31

Promisesを正しく理解していないと思います。 returnステートメントは、Promiseが解決される前に呼び出されるため、空の文字列が返されます。

これに取り組むための1つの方法は、次のような約束全体を返すことです。

// Gets the fullname of the customer from an id.
tj_customer_name(id) {
  let customer_name = '';

  return fetch(`/customers/${id}.json`, {
    headers: API_HEADERS,
    credentials: 'same-Origin'
  })
  .then((response) => {
    if(response.ok) {
        return response.json();
    } else {
        throw new Error('Server response wasn\'t OK');
    }
  })
  .then((json) => {
    return json.first_name.concat(' ').concat(json.last_name);
  });
}

または、このようなasync/awaitを使用して、ES7アプローチを使用できます

async function tj_customer_name(id) {
    const response = await fetch('some-url', {});
    const json = await response.json();

    return json.first_name.concat(' ').concat(json.last_name);
}

ご覧のとおり、2番目のアプローチはよりクリーンで読みやすいです。

結果は、関数を呼び出すコードで同じになります

tj_customer_name(1).then(fullName => {
    console.log(fullName);
});

または

async function something() {
    const fullName = await tj_customer_name(1);
    console.log(fullName);
}
21
kudlajz

フェッチは非同期で、promiseを返すため、その性質上(.thenを使用して)非同期的にのみ監視できます。

おそらく、関数で作成したプロミスチェーンを返し、チェーンの最後のcustomer_nameコールバックで.thenを返す必要があります。

// Gets the fullname of the customer from an id.
tj_customer_name(id) {

 // return the entire promise chain
 return fetch(`/customers/${id}.json`, {
   headers: API_HEADERS,
   credentials: 'same-Origin'
 })
 .then((response) => {
   if(response.ok) {
     return response.json();
   } else {
     throw new Error('Server response wasn\'t OK');
   }
 })
 .then((json) => {
   const customer_name = json.first_name.concat(' ').concat(json.last_name);
   return customer_name; // return the customer_name here
 });
}

// later, use the function somewhere
this.tj_customer_name(21).then((customer_name) => {
    // do something with the customer_name
});

PS:潜在的なネットワークの問題を処理するために.catchハンドラーを追加することを忘れないでください(参照: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch #Checking_that_the_fetch_was_successful

7
nils