Skip to Content
JavaScriptAdvanceAsynchronous JavaScript

Asynchronous JavaScript ⏳

JavaScript runs single-threaded, so async patterns keep apps responsive.

1) Callbacks 📞

readFile("config.json", (error, data) => { if (error) return console.error(error); console.log(data); });
  • Pass a function to run when work completes.
  • Beware “callback hell” (deep nesting) and remember to handle errors first.

2) Promises 🤝

fetch("/api/todos") .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error)) .finally(() => console.log("done"));
  • Promise states: pending → fulfilled/rejected.
  • Chain then/catch to compose asynchronous steps.

3) async/await ✨

async function loadTodos() { try { const response = await fetch("/api/todos"); const data = await response.json(); return data; } catch (error) { console.error(error); } }
  • Syntactic sugar over Promises; use try...catch for errors.
  • Run in parallel with await Promise.all([...]).

4) Event Loop 🌀

  • JS executes stack frames; asynchronous callbacks queue up in the task or microtask queue.
  • Microtasks (Promises) run before the next rendering tick; macrotasks (timers, DOM events) run afterwards.

Order Example

console.log("start"); setTimeout(() => console.log("timeout")); Promise.resolve().then(() => console.log("microtask")); console.log("end"); // start, end, microtask, timeout

Key Takeaways ✅

  • Callbacks were first, Promises add structure, async/await keeps code readable.
  • Always handle errors and consider concurrency with Promise.all/Promise.race.
  • Understanding the event loop explains why microtasks run before timers.

Recap 🔄

Async JavaScript keeps the UI smooth: wrap work in Promises, await results cleanly, and leverage knowledge of the event loop to avoid surprises.

Last updated on