Aiuto con async/await: codice restituisce undefined anziché dati API

👤 Iniziato da @delfinorinaldi
📅 10/06/2025 10:50
📁 Programmazione 🌐 IT
Avatar di delfinorinaldi
Ciao a tutti, sto impazzendo con una funzione asincrona in JavaScript. Devo recuperare dati da un'API esterna usando fetch, ma quando chiamo la mia funzione getDatiUtente(), ottengo sempre 'undefined'. Ecco il codice che uso:

```javascript
async function getDatiUtente() {
const response = await fetch('https://api.example.com/user/123');
const data = response.json();
return data;
}

const risultato = getDatiUtente();
console.log(risultato); // Output: undefined
```
Ho verificato l'endpoint con Postman e funziona, il problema è nell'implementazione. Sospetto un errore nella gestione delle promise o nella sintassi, ma dopo tre ore di tentativi non riesco a capire dove sbaglio. Qualcuno può spiegarmi perché response.json() non restituisce i valori attesi? Ho dimenticato qualche passaggio fondamentale? Ogni consiglio è ben accetto, grazie!
Avatar di genzianalombardo95
Ah, capisco il problema! Quel maledetto `undefined` che spunta quando meno te l'aspetti...

Il punto cruciale è questo: **`response.json()` è a sua volta una Promise asincrona**, e ti sei dimenticato di mettere `await` anche lì. Senza `await`, `data` diventa una Promise in sospeso, non i dati effettivi. Inoltre, quando chiami `getDatiUtente()`, devi gestire l'attesa del risultato.

Ecco la correzione:

```javascript
async function getDatiUtente() {
const response = await fetch('https://api.example.com/user/123');
const data = await response.json(); // Aggiungi qui l'await!
return data;
}

// Per ottenere il risultato DEVI usare:
getDatiUtente()
.then(risultato => console.log(risultato))
.catch(error => console.error("Errore:", error));

// Oppure in un altro async/await:
(async () => {
const risultato = await getDatiUtente();
console.log(risultato);
})();
```

**Spiegazione extra:**
- Senza il secondo `await`, `response.json()` restituisce una Promise non risolta, quindi `return data` restituisce una Promise vuota (da qui l'`undefined`).
- Quando chiami la funzione, non puoi assegnarla direttamente a una variabile perché l'operazione è asincrona: serve `.then()` o un wrapper `async`.

Prova così e fammi sapere se risolvi! 💻✨ (So cosa si prova a fissare il codice per ore, ti mando un abbraccio virtuale!)
Avatar di rosmundatesta24
Ecco, ti spiego subito il problema! Hai fatto un errore molto comune con le Promise - response.json() è asincrona e devi mettere un altro await davanti. Ma c'è di più: quando chiami getDatiUtente(), stai ignorando completamente che è una funzione async e quindi restituisce una Promise!

Ti consiglio di modificare così:
```javascript
async function getDatiUtente() {
try {
const response = await fetch('https://api.example.com/user/123');
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return await response.json(); // doppio await come suggerito
} catch (error) {
console.error('Errore nel fetch:', error);
throw error; // rilancia per gestirlo dove chiami la funzione
}
}

// Per usarla correttamente:
(async () => {
try {
const risultato = await getDatiUtente();
console.log(risultato);
} catch (e) {
// gestisci errori qui
}
})();
```

Pro tip: aggiungi sempre il controllo response.ok e gestisci gli errori con try/catch, altrimenti rischi di impazzire con fetch silenziosamente fallito! Se hai dubbi su come gestire le Promise, prova a leggere "You Don't Know JS" di Kyle Simpson, spiega benissimo questi concetti.
Avatar di fabriziapalmieri
@genzianalombardo95 e @rosmundatesta24 hanno ragione. Il problema principale è che **`response.json()` è una Promise**, quindi devi aspettare che si risolva con `await`. Senza, `data` conterrà solo una promessa non risolta, non i dati effettivi. Ecco la correzione chiara:

```javascript
async function getDatiUtente() {
const response = await fetch('https://api.example.com/user/123');
const data = await response.json(); // 🔥 Manca l'await qui
return data;
}
```

Poi, quando chiami `getDatiUtente()`, **non puoi loggarla direttamente** perché è una funzione async: restituisce sempre una Promise. Usa `.then()` o un blocco async/await:

```javascript
// Opzione 1
getDatiUtente().then(risultato => console.log(risultato));

// Opzione 2 (se sei in un contesto async)
(async () => {
const risultato = await getDatiUtente();
console.log(risultato);
})();
```

**Extra:**
Aggiungi un controllo per `response.ok` per evitare di processare risposte con stato di errore (es. 500). E usa `try/catch` per gestire eventuali errori di rete o API. Ti salva la vita in debugging.

Se sei su un ambiente che supporta **top-level await** (es. moduli ES6), puoi semplificare:
```javascript
const risultato = await getDatiUtente();
console.log(risultato);
```
Ma solo se sei nel contesto giusto, altrimenti torna a `.then()` o IIFE. Non serve a niente loggare direttamente la Promise: ti darà sempre `undefined`.
Avatar di delfinorinaldi
Grazie @fabriziapalmieri, chiarissimo. Avevo proprio saltato l'`await` su `response.json()` e cercavo di loggare la Promise direttamente. Adesso ho fixato con il tuo esempio:

```javascript
async function fetchDati() {
try {
const res = await fetch('https://api.example.com/data');
if (!res.ok) throw new Error(`Errore ${res.status}`); // utilissimo sto controllo
return await res.json();
} catch (err) {
console.error("Errore nel fetch:", err);
}
}

// Uso con IIFE
(async () => {
const dati = await fetchDati();
console.log(dati); // Ora funzia!
})();
```

Il `try/catch` mi ha già salvato da un 404. Direi che il problema è risolto alla radice.
Avatar di niccolocaruso72
Benissimo @delfinorinaldi, finalmente hai inchiodato quel maledetto `undefined`! Quell'`await` mancato su `response.json()` è una trappola in cui ci siamo cascati tutti, porca miseria. Sono contento che il controllo `res.ok` ti abbia già salvato il codice - dimostra che quei check sugli status HTTP non sono "nice to have" ma **essenziali**, specie con API esterne che possono tradirti quando meno te lo aspetti.

Però permettimi un appunto sul `try/catch`: così com'è, stai ingoiando l'errore. Se `fetchDati()` viene chiamata da altri punti del codice, chi la usa non saprà mai se qualcosa è andato storto! Meglio aggiungere un `throw` dopo il log:

```javascript
catch (err) {
console.error("Errore nel fetch:", err);
throw err; // RILANCIA per chi chiama la funzione!
}
```

Così chi usa `fetchDati` può gestire a sua volta l'errore (magari mostrando un alert all'utente).

Detto questo, quel IIFE è pulito e funzionale - quando vedo codice che passa da "disastro totale" a "funzia!" mi scatta una soddisfazione bestiale. Sei sulla buona strada, continua così! 💪
Avatar di almapalmieri
Assolutamente d'accordo con te, @niccolocaruso72! Quel `throw err` dopo il log è **fondamentale** per non nascondere gli errori sotto il tappeto, specie in progetti scalabili. Ti dirò - io stessa ho imparato a mie spese, dopo un weekend perso a debugare un 500 silenziato da un catch "mangia-errori".

Un altro consiglio che do sempre: se vuoi rendere la gestione ancora più robusta, aggiungi un `Error` personalizzato con contesto aggiuntivo:

```javascript
catch (err) {
const customError = new Error(`Fetch fallito: ${err.message} (endpoint: ${url})`);
console.error(customError);
throw customError;
}
```
Così in produzione sai esattamente quale endpoint ha fallito senza scavare nei log.

Però adoro l'energia con cui spingi per le best practice - quel "porca miseria" mi ha strappato un sorriso, è la rabbia sacra di chi ha combattuto con le promise a 3AM! 😄 Quella combinazione di controlli stretti (`res.ok`) + errori espliciti è il pane quotidiano per chi non vuole incappare in bug demoniaci.

Continua così, il tuo feedback è oro per chi impara! 👏
Avatar di eligiorizzo75
Ciao @almapalmieri, hai centrato il punto con quel consiglio sui custom error – io ci tengo tantissimo a non lasciare buchi nel codice, e mi secca da morire quando un errore banale si trasforma in un incubo da debuggare, come è capitato a me con un API flaky durante un progetto freelance. Aggiungere l'endpoint nel messaggio è geniale, ma io vado un passo oltre: includi sempre un timestamp o i dati di input per tracciare tutto al volo. Quella rabbia per le promise alle 3AM? La conosco bene, e mi fa piacere vedere che spingi per best practice solide come le tue. Continuiamo a condividere questi trucchi, perché roba del genere rende tutti più leali verso il codice che scriviamo. Magari prova a leggere "You Don't Know JS" se non l'hai già fatto; ha salvato il mio sanity in più di un'occasione! 😏

La Tua Risposta

💬

Vuoi partecipare alla discussione?

Accedi o registrati per scrivere la tua risposta e unirti alla conversazione!