Tengo un fragmento de código donde busco un archivo JSON de mi disco local:
var modelData = fetch("./modelData.json") .then((res) => res.json()) .then((val) => console.log(val)
Y haciendo esto puedo ver perfectamente los datos JSON en la consola de mi navegador. Sin embargo, cuando hago esto:
var modelData = fetch("./modelData.json") .then((res) => res.json()) .then((val) => val) console.log(modelData)
Veo una promise(pending)
en mi consola. Sé cómo funciona Async JS, y sé que el then() encadenado se activa solo cuando se resuelve la promesa anterior. Mi pregunta es, en mi segundo bloque then(), ¿por qué puedo ver los datos cuando los consola.log() pero no puedo ver la fecha cuando los devuelvo desde la misma función donde estaba consola.registrándolos?
Además, si considero el hecho de que tal vez en el segundo caso la promesa no se cumplió cuando la consola. Lo registré, debido a la naturaleza asíncrona de fetch(), probé lo siguiente:
var modelData = fetch("./modelData.json") .then((res) => res.json()) .then((val) => val) setTimeout(()=>console.log(modelData), 1000)
pensando que una vez cumplida la promesa, seguramente obtendré mi valor. pero luego entiendo
Promesa (cumplida)
. ¿Alguien puede decirme lo que me estoy perdiendo? Estaré muy agradecido por cualquier ayuda.
Al principio es difícil entender estos conceptos. Voy a cambiar un poco tu código:
var promise = fetch("./modelData.json"); promise.then((res) => res.json()) .then((val) => console.log(val); console.log(modelData)
Como ves, es el mismo código. Creo una promesa y establezco lo que quiero hacer cuando se resuelva. Lo que obtienes es un objeto (la promesa) que ejecutará tu búsqueda y, si tiene éxito, invocará tu función "entonces".
Pero la variable "promesa" (modelData en su pregunta) es siempre una promesa. Nunca tiene datos sobre su modelo.
Imagina que en lugar de buscar, invocas alguna función setTimeout con 60 segundos de retraso. Su console.log se ejecutará inmediatamente y es imposible que en ese momento tenga los resultados de su función, aparte de que el objeto es una promesa, no sus datos obtenidos. Pero depure el código, imagine que ingresa el código de promesa y después de 60 segundos, ingresa la función "entonces". Dentro de esa función es donde tienes disponibles tus datos. Es por eso que trabajas con los resultados dentro de la función entonces, nunca fuera.
No puedes "desenvolver" una Promesa, pero ni siquiera deberías tener que hacerlo.
Una Promesa no es un marcador de posición para los datos reales que mágicamente se convertirán en ellos una vez que lleguen. Es un identificador, a través del cual puede acceder a los datos de la misma manera sin importar si ya llegaron o llegarán más tarde.
Por esa razón, todo lo que then
devuelva desde una devolución de llamada siempre estará envuelto en otra promesa, por lo que aún no es posible acceder directamente desde el exterior.
Si tenemos el siguiente código,
//`Promise.resolve` is added just for the sake of illustration (it wraps its argument in a promise similarly to what `then` does) const p1 = Promise.resolve(fetch("./modelData.json")) const p2 = p1.then((res) => res.json()) const p3 = p2.then((val) => val)
...podemos visualizar la estructura así:
Promise.resolve( fetch(...) ) vvvvvvvvvvvvvvv vvvvvvvvvv +------+++++++++++++++ ++++++++++ | | v vvv p1 ---------------- .then(res => res.json()) vvvv vvvvvvvvvv +-------------------++++ ++++++++++ | +-----+ | | v vvv p2 ---------------- .then(val => val) vvvv vvv +-------------------++++ +++ | +------+ | | vv p3 • • • • • • • • .then(... => ...)
Como puede ver en eso, se requeriría otro .then
para acceder al valor en p3
.
Es por eso que console.log
ging dentro de un then
puede imprimir el valor real, mientras que console.log
ging outside solo le dará una promesa.
La función fetch()
y el método then()
devuelven un objeto Promise
. Asignó ese objeto Promise
a modelData
y permanecerá como un objeto Promise
y no se reasignará automáticamente al valor cumplido.
Para obtener el valor completo, puede usar el método then()
o await keyword
.
// name it `modelPromise` to be clear const modelPromise = fetch("./modelData.json") .then(res => res.json()) .then(val => val) modelPromise.then(val => console.log(val)) // `await` can only be used inside an async function async function main() { const value = await modelPromise; console.log(value); }