JavaScript & TypeScript DISCUSSION

Why does my JavaScript function return undefined instead of the fetch response?

Started by vaibhavpatil JavaScript promisesasync awaitfetch APIevent loopasynchronous return value
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

Why does my JavaScript function return undefined instead of the fetch response?

vaibhavpatil JavaScript & TypeScript Forum
#1

My dashboard page requests a reading from an ESP32: function getTemp() { let result; fetch('/api/temp').then(r => r.json()).then(d => { result = d.value; }); return result; }. Calling getTemp() always gives undefined, although a console.log inside the callback prints the correct value a moment later.

I tried returning the value from inside the then callback, and also a while loop that waits for result to be set; the loop just hangs the page. How do I get the value out of an asynchronous call?

Community replies 5

Re: Why does my JavaScript function return undefined instead of the fetch response?

#2

fetch starts the request and returns a Promise immediately; the network reply arrives milliseconds later. Your function's statements run in order without waiting: start the request, register the callbacks, return result, which is still undefined. Only after the current code has finished and the response has arrived does the callback run and assign result, and by then nobody is looking.

The while loop cannot work because JavaScript runs your code on a single thread with an event loop, and callbacks only run when the current code returns to that loop. A loop that never returns blocks the very callback it is waiting for, along with rendering and input.

Re: Why does my JavaScript function return undefined instead of the fetch response?

#3

You cannot return the value itself; you return the Promise and let the caller wait for it. With async and await: async function getTemp() { const r = await fetch('/api/temp'); const d = await r.json(); return d.value; }. await pauses this function, not the thread, until the promise settles.

An async function always returns a Promise, so the caller must wait as well: const t = await getTemp(); inside another async function or at the top level of an ES module, or getTemp().then(t => show(t));. Asynchrony spreads up the call chain. The top is usually an event handler or start-up code that fires the call and updates the page when the result arrives.

Re: Why does my JavaScript function return undefined instead of the fetch response?

#4

Add error handling, because fetch only rejects on a network failure. An HTTP 404 or 500 resolves normally, so check if (!r.ok) throw new Error('HTTP ' + r.status); before parsing. Wrap the awaits in try/catch, or put a .catch() on the chain, so that a failure shows a message instead of an unhandled rejection in the console.

A microcontroller can be unreachable, so give the request a timeout too: fetch(url, { signal: AbortSignal.timeout(3000) }) rejects after 3 seconds in current browsers instead of waiting for the browser's much longer default.

Re: Why does my JavaScript function return undefined instead of the fetch response?

#5

The usual remaining bugs are a missing await or return. const t = getTemp(); without await gives you a Promise object, and t + 1 produces the string "[object Promise]1". In a then chain every callback must return its value: .then(r => { r.json(); }), with braces and no return, passes undefined to the next step.

forEach does not wait for async callbacks either; ids.forEach(async id => { await load(id); }); fires them all and carries on. Use for (const id of ids) { await load(id); } for sequential requests or await Promise.all(ids.map(id => load(id))) for parallel ones. Three requests of 200 ms each take about 600 ms the first way and about 200 ms the second.

Re: Why does my JavaScript function return undefined instead of the fetch response?

#6

For a periodically refreshed reading, avoid setInterval with an async function when a request can take longer than the interval; calls pile up and replies can arrive out of order. Use a loop that awaits the request and then a delay: const sleep = ms => new Promise(res => setTimeout(res, ms)); and while (running) { show(await getTemp()); await sleep(1000); }. Unlike your busy-wait, this loop is fine, because each await hands control back to the event loop.

Older callback-style APIs can be wrapped once, new Promise((resolve, reject) => api.read((err, v) => err ? reject(err) : resolve(v))), and awaited like everything else. If the device produces data continuously, a WebSocket or Server-Sent Events connection is a better fit than polling.

TEP COMMUNITY