Cómo devolver una respuesta de una llamada asíncrona: guía completa para JS

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

«¡Ejecuto una función y devuelve undefined!» — ¿un dolor familiar?

\n

Imagina: escribes código en JavaScript, haces una solicitud a una API, esperas los datos… y recibes undefined. O peor — Promise {<pending>}. Te desanimas, quieres cerrar el navegador y hacerte monje.

\n

No te apresures. Este problema atormenta incluso a desarrolladores experimentados. No en vano la pregunta «How do I return the response from an asynchronous call?» en Stack Overflow ha acumulado miles de visitas y cientos de respuestas. Hoy lo resolveremos de una vez por todas.

\n

En este artículo aprenderás:

\n
    \n
  • Por qué return no funciona como estás acostumbrado
  • \n
  • Cómo dominar la asincronía con callbacks, promesas y async/await
  • \n
  • Qué enfoque elegir para tu proyecto
  • \n
\n

¡Allá vamos!

\n\n

¿Por qué return no devuelve los datos?

\n

Vamos al grano. Aquí tienes un ejemplo clásico:

\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 todo está bien?\n    });\n}\n\nconst user = getUserData(42);\nconsole.log(user); // undefined
\n\n

¿Te resulta familiar? Escribiste return data dentro de .then(), pero afuera obtuviste undefined. ¿Por qué?

\n

JavaScript es de un solo hilo y no bloqueante. Cuando llamas a fetch, no espera la respuesta del servidor. En su lugar, «aplaza» la ejecución del callback y pasa inmediatamente a la siguiente línea. Y la siguiente línea es console.log(user), donde user aún no está definido.

\n

Tu función getUserData termina antes de que llegue la respuesta del servidor. No devuelve nada (devuelve undefined), y los datos quedan «en el aire».

\n

¿Cómo solucionarlo? Hay tres formas principales.

\n\n

Forma 1: Callbacks — el abuelo de la asincronía

\n

Antes, antes de que existieran las promesas, todas las operaciones asíncronas se hacían con callbacks. Pasas una función que se ejecutará cuando lleguen los datos.

\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); // Llamamos al callback con los datos\n    })\n    .catch(error => {\n      callback(null, error); // O pasamos el error\n    });\n}\n\n// Uso:\ngetUserData(42, (data, error) => {\n  if (error) {\n    console.error('Error:', error);\n    return;\n  }\n  console.log('Datos del usuario:', data);\n});
\n\n

Ventajas: simplicidad, funciona en todas partes.

\n

Desventajas: si anidas varios callbacks, obtienes un «infierno de callbacks» (callback hell). El código se vuelve ilegible.

\n\n
getUserData(42, (data1) => {\n  getPosts(data1.id, (data2) => {\n    getComments(data2[0].id, (data3) => {\n      // ... y así sucesivamente\n    });\n  });\n});
\n\n

El JavaScript moderno se alejó de esto. Pero entender los callbacks es necesario — son la base de todos los demás enfoques.

\n\n

Forma 2: Promesas — salvadoras de la legibilidad

\n

Una promesa es un objeto que representa una «promesa» de devolver un valor en el futuro. Tiene tres estados: pending (pendiente), fulfilled (cumplida) y rejected (rechazada).

\n

Volvamos a nuestro ejemplo. En lugar de un callback, devolvemos la promesa misma:

\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('La red no está en orden');\n      }\n      return response.json();\n    });\n}\n\n// Uso:\nconst userPromise = getUserData(42);\n\nuserPromise\n  .then(data => {\n    console.log('Datos del usuario:', data);\n  })\n                

Blogs

Book Recommendations