Callbacks and Promises

Originally JavaScript used callbacks for async tasks. Promises provide a cleaner, chainable way to handle success and failure.

// Callback style
function fetchData(url, callback) {
  setTimeout(() => {
    callback(null, { data: 'Sample' });
  }, 1000);
}
fetchData('/api', (err, result) => {
  if (err) console.error(err);
  else console.log(result);
});

// Promise style
function fetchDataPromise(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ data: 'Sample' });
    }, 1000);
  });
}
fetchDataPromise('/api')
  .then(result => console.log(result))
  .catch(err => console.error(err));

Key Points

  • Callbacks can lead to “callback hell” when nested deeply.
  • Promises have .then() and .catch() for chaining and error handling.
  • Promise.all() runs multiple promises in parallel and waits for all to settle.

Async/Await

async functions let you write asynchronous code in a synchronous style. Use await to pause until a promise resolves.

async function loadData() {
  try {
    const user   = await fetchDataPromise('/api/user');
    const posts  = await fetchDataPromise('/api/posts');
    console.log(user, posts);
  } catch (err) {
    console.error('Error loading data:', err);
  }
}

// Running multiple awaits concurrently
async function loadAll() {
  try {
    const [user, posts] = await Promise.all([
      fetchDataPromise('/api/user'),
      fetchDataPromise('/api/posts')
    ]);
    console.log(user, posts);
  } catch (err) {
    console.error(err);
  }
}

Key Points

  • async functions always return a promise.
  • await can only be used inside async functions.
  • Use try/catch around await to handle errors.
  • Promise.all() for parallel execution.