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:
It is worth adding that the returned Promise is not accessible, for example in:
essaPromise.value
– Anonymous Fox
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 infetch
).– Luiz Felipe
@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?
– Anonymous Fox
Its function
checkUserSubscription
is that it should beasync
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))– Pedro Camara Junior
@Pedrocamarajunior I’ll try that
– Anonymous Fox