How to assign the result of a Promise to a variable?

Asked

Viewed 2,366 times

7

Even reading this one another question of the site, I still do not understand why I can not withdraw a value from within a Promise. How do I do that kind of assignment?

The idea is to execute several promises (gather data to generate information). I leave below an example in which I can print the data to the console, but I cannot assign the variable tam.

function recuperaDados() {
  return new Promise((resolve, reject) => {
    request.get('http://localhost:8080/api/tamanhos', (error, _, body) => {
      if (error) {
        reject(error);
      }
      resolve(body);
    });
  });
}

app.get('/', (req, res) => {
  // Quero que o resultado de `recuperaDados()` venha para cá.
  let tams;

  recuperaDados()
    .then((body) => {
      // Consigo imprimir ao console:
      console.log(body);

      // Mas esta atribuição não funciona:
      tams = body;
    })
    .catch(console.error);

  console.log(typeof tams); //-> undefined
  res.send(tams); // Não exibe nada.
});

Where am I wrong? Would I have to do several pomises, one inside the other? Following the best practices, what would be the best solution?

1 answer

11


TL;DR: If you want to follow good practices, you cannot assign the solved value of a Promise for a variable that is outside the callback of then or catch or asynchronous function. Read the following answer to understand why.


Javascript is single-threaded[EN] and therefore operates through a event loop. Taking this statement into account, he cannot expect a Promise resolve to continue running the rest of the application (unlike languages such as PHP), as this would block the entire event loop, preventing other interactions on the page.

Taking into account that a Promise will conclude at some point that we have no science (in 5 milliseconds, 5 seconds or even more time), we have no way to define the time the promise will be "carrying". The most correct way for you to access the resolved data of a Promise is through the then, which will receive the solved amount, or the catch, which will carry out any error negotiations.

Be aware, however, that although you can rather assign the solved value of a promise out of the callback of then, that one is not a good practice (and can even lead your code to errors) precisely because, as I said above, you cannot accurately determine the time at which each Promise will take time to complete.

So, following best practices, to access the solved data of a Promise, you have two options:

Use the then:

app.get('/', (req, res) => {
  recuperaDados()
    .then((dados) => {
      // Você terá que tratar os dados aqui dentro.
      // Não poderá passar os dados da variável `dados` para fora
      // do escopo desse callback de nenhum modo. 

      // Note a seguir que eu posso fazer o uso dos dados da forma como eu desejar
      // dentro desse callback. Logo, não há motivo para querer levar a variável `dados`
      // para fora do escopo atual. :)
      res.send('Dados: ' + JSON.stringify(dados))
    })
})

Utilise asynchronous function:

To use asynchronous function, you must use the operator await to wait for the resolution of the returning functions Promise:

// Note abaixo que marquei a função como assíncrona adicionando o prefixo "async".
//           ↓↓↓↓↓
app.get('/', async (req, res) => {
  // O `await` irá bloquear o código *somente dentro dessa função* até que
  // o valor da promessa seja devidamente resolvido:
  const dados = await recuperaDados()

  // Como utilizamos o `await` acima, esse código só será executado
  // quando os dados da promessa estiverem "prontos":
  res.send('Dados: ' + JSON.stringify(dados))
})

Remember that when using asynchronous functions, you should use the await so that you await the conclusion of the Promise (resolution or rejection), otherwise you will be assigning to the variable the promise itself, not its resolution or error value. The operator await going stop execution within asynchronous function until the Promise be resolved.

Additional interesting reading or for deepening:

Browser other questions tagged

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