How to return the value of a function that uses Javascript promises?

Asked

Viewed 111 times

1

I have a function that should check if a user is enrolled in Stripe. For this is made a request to a third server that returns an array of users.

When I make the request, a promise is returned: Promise {state: 'pending'}. To solve this I did the following:

fetch(url, { method: 'POST' }).then(async (res) => {
  await res.json()
  // Código executa perfeitamente como desejado dentro desse bloco...
});

However, this creates a problem: Like the fetch is involved in a function (function M() { fetch(...) }) and it is not possible to withdraw the value from within the promise without a then, how do I get M return the response of fetch?

My complete code:

checkUserSubscription: (email) => {
        var response ={status: 'inactive'}
        
        const costumers = fetch(`url/payment/list`, {method: 'POST'})
        .then(async(res) => {
           let costumers = await res.json()
           return costumers
        })
        console.log(costumers) //Promise {state: 'pending}, mas com fullfiled e value
        for (var costumer in costumers) {
            if (costumers[costumer].email == email) {
                response = {
                    email: email,
                    id: costumers[costumer].id,
                    status: 'active'
                }                
            }
        }

        return response // {status: 'inactive'}
    }

Answer:

inserir a descrição da imagem aqui

  • It is worth adding that the returned Promise is not accessible, for example in: essaPromise.value

  • 2

    Do not fight against the asynchronous nature of Javascript, it is a war that will always be doomed to failure. Instead, embrace the asymchronism of language. In this case, this M (for example) should return the promise (or a new promise, derived from that originating in fetch).

  • @Luizfelipe I’m not trying to fight, just get a little confused because I’ve dealt with fetch, but this had never happened before. You could make it clearer by code what you mean?

  • Its function checkUserSubscription is that it should be async and then, you expect (await) that the returned file in fetch will be resolved. Not too many details: checkUserSubscription: async () => ː /* ... */ customers = await fetch(). then(res => res.json))

  • @Pedrocamarajunior I’ll try that

1 answer

3


As I said in this another answer, Javascript has an intrinsically asynchronous nature. Moreover, once a function works with some asynchronous operation, the caller of function accurate to suit the asynchrony as well.

This suitability of the caller can occur in two main ways:

  • Callback, which is the old way of dealing with asynchronism in Javascript;
  • Promise, which is the recommended way to deal with asynchronism in current Javascript code.

I will deal with this answer exclusively on promises, but similar ideas can be applied with callbacks.


Once a function that performs asynchronous operation in Javascript is called, the caller needs to deal with asynchronous operation. And this, given that asynchronous operations take time to be resolved, implies that the calling code needs to "wait" for the completion of the operation.

In the case of promises, this is done with the then.

In case you implement a function that uses asynchronous operation and ensure that the caller of your function also hold on by the completion of the process, you must return the promise. It is no use trying to "remove the value of a promise", because this is not possible (in order to avoid gambiarras). I discuss this further at How to assign a Promise result to a variable?.

What you need to do is return the promise. This way, the code that calls your function can use the then (or await, if it is asynchronous function) to await by the resolution of your function.

Below I leave an example to demonstrate:

// Função que chama a API do GitHub para determinar
// o número de repositórios públicos de um usuário.
function getRepoCount(username) {
  const promise = fetch(`https://api.github.com/users/${username}`)
    .then((response) => response.json())
    .then((json) => {
      return `O usuário ${json.login} tem ${json.public_repos} repositório(s).`;
    });
    
  // Note que eu estou retornando a promessa.
  // Assim, quem chamar esta função poderá utilizar o `then` (ou `catch`) na promessa que retornamos.
  return promise;
}

// Função que chama:
function main() {
  getRepoCount('lffg')
    .then((message) => console.log('Mensagem recebida: ' + message))
    .catch((error) => console.log('Whoops! Algo deu errado!: ' + error.message));
}

main();

Note in the above code that the function getRepoCount that I have implemented performs asynchronous operation. In this way, how can we make those who call upon getRepoCount are aware of when the operation has been completed? The answer is: Returning to the promise!

Thus, you ensure that all function callers can handle the promise, which means awaiting resolution (Promise.prototype.then) or deal with any mistakes (Promise.prototype.catch or second argument from then). :)


In your case (and with some code improvements), it would look something like this:

function checkUserSubscription(email) {
  return fetch(`url/payment/list`, { method: 'POST' })
    .then((response) => response.json())
    .then((costumers) => {
      // Note que, de dentro da promessa, podemos retornar qualquer valor.
      // Nesse caso, estamos retornando o resultado da operação
      // `Array.prototype.find`, que, neste caso, irá procurar, dentro do array
      // `customers`, o usuário com o e-mail fornecido.
      //
      // O valor que retornamos de dentro dessa promessa será passado para a
      // promessa que a função `checkUserSubscription` retorna.
      return costumers.find((customer) => customer.email === email);
    });
};

checkUserSubscription('[email protected]')
  .then((customer) => {
    // `customer` será o objeto de `customers` referente ao e-mail.
    // Caso não existir o usuário com o e-mail fornecido no array, `customer`
    // será `undefined`. Esse comportamento se deve ao `Array.prototype.find`.
    console.log(customer);
  })
  .catch((error) => {
    // Trate o eventual erro.
  });

And, of course, you can use asynchronous functions to simplify a bit:

async function checkUserSubscription(email) {
  const response = await fetch(`url/payment/list`, { method: 'POST' });
  const costumers = await response.json();

  // Pode parecer que estamos retornando "somente" o consumidor a ser encontrado,
  // mas, na verdade, estamos retornando uma promessa. Isso ocorre porque,
  // implicitamente, TODA função assincrona retorna uma promessa.
  //
  // E, como dito acima, o que precisa ser feito para que o chamador esteja
  // "ciente" do assincronismo da função que chamou é RETORNAR A PROMESSA.
  return costumers.find((customer) => customer.email === email);
}

// Note que nada muda na interface do chamador. Funções assíncronas são,
// basicamente, açúcar sintático para operações comuns relacionadas a promessas.
checkUserSubscription('[email protected]')
  .then((customer) => {
    console.log(customer);
  })
  .catch((error) => {
    // Trate o eventual erro.
  });

As a suggestion, try to understand deeply about promises, which are essential to the Javascript domain. In addition, knowing about asynchronous functions may also be useful. I recommend:

  • Thank you very much. I ended up identifying the error later, but even so, your answer was enlightening.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.