Como retornar uma resposta de uma chamada assíncrona: guia completo para JS

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

«Eu executo uma função, e ela retorna undefined!» — uma dor familiar?

\n

Imagine: você está escrevendo código em JavaScript, faz uma requisição a uma API, espera os dados… e recebe undefined. Ou pior — Promise {<pending>}. Você desanima, quer fechar o navegador e virar monge.

\n

Não se apresse. Esse problema aflige até desenvolvedores experientes. Não é à toa que a pergunta «How do I return the response from an asynchronous call?» no Stack Overflow tem milhares de visualizações e centenas de respostas. Hoje vamos resolvê-la de uma vez por todas.

\n

Neste artigo, você aprenderá:

\n
    \n
  • Por que o return não funciona como você está acostumado
  • \n
  • Como domar a assincronicidade com callbacks, promises e async/await
  • \n
  • Qual abordagem escolher para o seu projeto
  • \n
\n

Vamos nessa!

\n\n

Por que o return não retorna os dados?

\n

Vamos direto ao ponto. Aqui está um exemplo clássico:

\n\n
function getUserData(userId) {\n  fetch(`https://api.example.com/users/${userId}`)\n    .then(response => response.json())\n    .then(data => {\n      return data; // Parece que está tudo certo?\n    });\n}\n\nconst user = getUserData(42);\nconsole.log(user); // undefined
\n\n

Familiar? Você escreveu return data dentro de .then(), mas do lado de fora recebeu undefined. Por quê?

\n

JavaScript é single-threaded e não bloqueante. Quando você chama fetch, ele não espera pela resposta do servidor. Em vez disso, ele «adiia» a execução do callback para depois e passa imediatamente para a próxima linha. E a próxima linha é console.log(user), onde user ainda não foi definido.

\n

Sua função getUserData termina antes que a resposta do servidor chegue. Ela não retorna nada (retorna undefined), e os dados ficam «suspensos no ar».

\n

Como corrigir isso? Existem três maneiras principais.

\n\n

Maneira 1: Callbacks — o avô da assincronicidade

\n

Antigamente, antes das Promises, todas as operações assíncronas eram feitas com callbacks. Você passa uma função que será chamada quando os dados chegarem.

\n\n
function getUserData(userId, callback) {\n  fetch(`https://api.example.com/users/${userId}`)\n    .then(response => response.json())\n    .then(data => {\n      callback(data); // Chama o callback com os dados\n    })\n    .catch(error => {\n      callback(null, error); // Ou passa o erro\n    });\n}\n\n// Uso:\ngetUserData(42, (data, error) => {\n  if (error) {\n    console.error('Erro:', error);\n    return;\n  }\n  console.log('Dados do usuário:', data);\n});
\n\n

Prós: simplicidade, funciona em qualquer lugar.

\n

Contras: se você aninhar vários callbacks, terá o «inferno dos callbacks» (callback hell). O código se torna ilegível.

\n\n
getUserData(42, (data1) => {\n  getPosts(data1.id, (data2) => {\n    getComments(data2[0].id, (data3) => {\n      // ... e assim por diante\n    });\n  });\n});
\n\n

O JavaScript moderno se afastou disso. Mas entender callbacks é necessário — eles estão na base de todas as outras abordagens.

\n\n

Maneira 2: Promises — salvadoras da legibilidade

\n

Uma Promise é um objeto que representa uma «promessa» de retornar um valor no futuro. Ela tem três estados: pending (pendente), fulfilled (resolvida) e rejected (rejeitada).

\n

Voltemos ao nosso exemplo. Em vez de um callback, retornamos a própria Promise:

\n\n
function getUserData(userId) {\n  return fetch(`https://api.example.com/users/${userId}`)\n    .then(response => {\n      if (!response.ok) {\n        throw new Error('Rede não está ok');\n      }\n      return response.json();\n    });\n}\n\n// Uso:\nconst userPromise = getUserData(42);\n\nuserPromise\n  .then(data => {\n    console.log('Dados do usuário:', data);\n  })\n                

Blogs

Book Recommendations