Skip to content
Retr0 Academy
Advanced JavaScript

Advanced JavaScript · 2 min read

Async/Await and Fetch in Depth

Promises, async/await, error handling with fetch, running requests in parallel, timeouts and cancellation.

Network calls, wallet signatures and timers all take time. JavaScript handles them with promises: objects that will settle later as either fulfilled (with a value) or rejected (with an error). async/await is syntax that lets you write promise code top to bottom.

await pauses only the async function. The page keeps running.
await pauses only the async function. The page keeps running.

fetch has two failure modes

js

async function getJson(url) {
  const res = await fetch(url);          // rejects only on network failure / CORS
  if (!res.ok) {                          // 404 and 500 still FULFILL the promise
    throw new Error("HTTP " + res.status);
  }
  return res.json();                      // also returns a promise
}

Sequential vs parallel

js

// Sequential: total time = a + b
const a = await getJson("/a");
const b = await getJson("/b");
 
// Parallel: total time = max(a, b)
const [a2, b2] = await Promise.all([getJson("/a"), getJson("/b")]);
CombinatorSettles whenRejects when
Promise.allall fulfilany one rejects (fail fast)
Promise.allSettledall settlenever; you inspect each result
Promise.racethe first settlesthe first settles with an error
Promise.anythe first fulfilsall reject (AggregateError)

Timeouts and cancellation

AbortController cancels a fetch. AbortSignal.timeout(ms) creates a signal that aborts on its own.

Query NEAR RPC with a timeout, in parallel
<button id="go">Fetch from 2 RPC endpoints</button>
<pre id="out">Click the button.</pre>

Edit this example in the Playground.

Open in Playground

Retrying with backoff

js

async function withRetry(fn, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try { return await fn(); }
    catch (e) {
      if (i === attempts - 1) throw e;
      await new Promise((r) => setTimeout(r, 2 ** i * 300)); // 300, 600, 1200 ms
    }
  }
}

Summary

Check res.ok, wrap awaits in try/catch, run independent requests with Promise.all or allSettled, and always bound network calls with a timeout. This is how a dApp stays responsive when an RPC node is slow.

Open in Playground

Saved in this browser.