Node.js7 min read

Async/Await: Clean Async Code

Master async/await for writing synchronous-looking asynchronous code. The modern way to handle async operations.

Sarah Chen
December 19, 2025
0.0k0

Async/Await: Clean Async Code

Async/await makes Promises look like synchronous code. It's the modern standard.

Basic Syntax

// Regular Promise
fetchUser()
  .then(user => console.log(user));

// Async/await
async function getUser() {
  const user = await fetchUser();
  console.log(user);
}

async Function

// Always returns a Promise
async function greet() {
  return 'Hello';
}

greet().then(msg => console.log(msg));  // Hello

await Keyword

async function loadData() {
  // Pauses here until Promise resolves
  const data = await fetchData();
  
  // Then continues
  console.log(data);
  return data;
}

Error Handling with try/catch

async function fetchUser(id) {
  try {
    const response = await fetch(`/api/users/${id}`);
    
    if (!response.ok) {
      throw new Error('User not found');
    }
    
    const user = await response.json();
    return user;
  } catch (error) {
    console.error('Error:', error.message);
    throw error;  // Re-throw if needed
  }
}

Sequential vs Parallel

// Sequential - slower
async function sequential() {
  const user = await fetchUser();    // Wait 1s
  const posts = await fetchPosts();  // Wait 1s
  // Total: 2s
}

// Parallel - faster
async function parallel() {
  const [user, posts] = await Promise.all([
    fetchUser(),    // Start immediately
    fetchPosts()    // Start immediately
  ]);
  // Total: 1s (max of both)
}

Async in Loops

// Sequential (one at a time)
async function processSequential(ids) {
  for (const id of ids) {
    const data = await fetchData(id);
    console.log(data);
  }
}

// Parallel (all at once)
async function processParallel(ids) {
  const promises = ids.map(id => fetchData(id));
  const results = await Promise.all(promises);
  return results;
}

Real-World Example

const fs = require('fs').promises;

async function processFile(inputPath, outputPath) {
  try {
    // Read file
    const content = await fs.readFile(inputPath, 'utf8');
    
    // Process
    const processed = content.toUpperCase();
    
    // Write result
    await fs.writeFile(outputPath, processed);
    
    console.log('Done!');
  } catch (error) {
    console.error('Failed:', error.message);
  }
}

Top-Level Await (ES Modules)

// In .mjs files or "type": "module"
const config = await fs.readFile('config.json', 'utf8');
console.log(config);

Arrow Functions with Async

const fetchData = async () => {
  const response = await fetch('/api/data');
  return response.json();
};

// In array methods
const results = await Promise.all(
  items.map(async (item) => {
    return await processItem(item);
  })
);

Common Patterns

// Retry logic
async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await fetch(url);
    } catch (error) {
      if (i === retries - 1) throw error;
      await delay(1000);  // Wait before retry
    }
  }
}

// Timeout
async function fetchWithTimeout(url, timeout = 5000) {
  const controller = new AbortController();
  const id = setTimeout(() => controller.abort(), timeout);
  
  try {
    const response = await fetch(url, { signal: controller.signal });
    clearTimeout(id);
    return response;
  } catch (error) {
    clearTimeout(id);
    throw error;
  }
}

Key Takeaway

Async/await is syntactic sugar over Promises. Use async to mark functions, await to pause for Promises, try/catch for errors. For parallel operations, use Promise.all(). It's the cleanest way to write async Node.js code.

#Node.js#Async/Await#Promises#Beginner