web-dev-qa-db-fra.com

Fetch: définir la variable avec la réponse fetch et le retour de la fonction

Je suis assez nouveau avec JavaScript et je réagis. J'ai un rappel d'un composant qui obtient un nom_client d'un serveur donné un identifiant. L'extraction fonctionne et le fichier console.log imprime correctement le nom complet, mais le nom_client dans le dernier .then n'est pas défini et les fonctions renvoient une chaîne vide. Pourquoi donc?

// 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

Je pense que vous ne comprenez pas correctement les promesses. L'instruction return sera appelée avant que la promesse ne soit résolue, retournant ainsi une chaîne vide.

Une façon de résoudre ce problème est de retourner la promesse entière comme ceci:

// 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);
  });
}

ou vous pouvez utiliser l'approche ES7, en utilisant async/wait comme ceci

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);
}

Comme vous pouvez le voir, la deuxième approche est beaucoup plus propre et lisible.

Le résultat sera le même dans le code qui appelle votre fonction

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

ou

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

Parce que l'extraction est asynchrone et renvoie une promesse, qui par sa nature ne peut être observée que de manière asynchrone (en utilisant .then).

Vous devriez probablement simplement renvoyer la chaîne de promesses que vous créez dans votre fonction et retourner customer_name à la fin .then rappel de la chaîne:

// 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: N'oubliez pas d'ajouter un .catch gestionnaire pour gérer les problèmes potentiels de réseau (voir: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful )

7
nils