javascript

examples

examples.js
// ============================================
// 18.1 Promise Combinators - Examples
// ============================================

// Helper function to simulate async operations
function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

function fetchData(id, time, shouldFail = false) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (shouldFail) {
        reject(new Error(`Failed to fetch ${id}`));
      } else {
        resolve({ id, data: `Data for ${id}` });
      }
    }, time);
  });
}

// --------------------------------------------
// 1. Promise.all() - Basic Usage
// --------------------------------------------

async function promiseAllBasic() {
  console.log('=== Promise.all Basic ===');

  const promises = [
    fetchData('user', 100),
    fetchData('posts', 200),
    fetchData('comments', 150),
  ];

  const startTime = Date.now();
  const results = await Promise.all(promises);
  const elapsed = Date.now() - startTime;

  console.log('Results:', results);
  console.log(`Time: ${elapsed}ms (parallel, not 450ms)`);
  // Time should be ~200ms (max of all), not 450ms (sum)
}

// promiseAllBasic();

// --------------------------------------------
// 2. Promise.all() - Order Preserved
// --------------------------------------------

async function promiseAllOrder() {
  console.log('\n=== Promise.all Order ===');

  // Even though they complete in different order...
  const promises = [
    delay(300).then(() => 'slow'),
    delay(100).then(() => 'fast'),
    delay(200).then(() => 'medium'),
  ];

  const results = await Promise.all(promises);
  console.log('Results in original order:', results);
  // ['slow', 'fast', 'medium'] - NOT completion order
}

// promiseAllOrder();

// --------------------------------------------
// 3. Promise.all() - Failure Behavior
// --------------------------------------------

async function promiseAllFailure() {
  console.log('\n=== Promise.all Failure ===');

  try {
    const results = await Promise.all([
      fetchData('user', 100),
      fetchData('posts', 50, true), // This will fail
      fetchData('comments', 150),
    ]);
    console.log('Results:', results);
  } catch (error) {
    console.log('Promise.all failed:', error.message);
    // Fails fast - doesn't wait for others
  }
}

// promiseAllFailure();

// --------------------------------------------
// 4. Promise.all() - Practical: Fetch Multiple APIs
// --------------------------------------------

async function fetchMultipleAPIs() {
  console.log('\n=== Fetch Multiple APIs ===');

  // Simulate API calls
  const apis = {
    users: () => delay(100).then(() => [{ id: 1, name: 'Alice' }]),
    products: () => delay(150).then(() => [{ id: 1, name: 'Widget' }]),
    orders: () => delay(80).then(() => [{ id: 1, total: 99.99 }]),
  };

  const [users, products, orders] = await Promise.all([
    apis.users(),
    apis.products(),
    apis.orders(),
  ]);

  console.log('Users:', users);
  console.log('Products:', products);
  console.log('Orders:', orders);
}

// fetchMultipleAPIs();

// --------------------------------------------
// 5. Promise.allSettled() - Basic Usage
// --------------------------------------------

async function promiseAllSettledBasic() {
  console.log('\n=== Promise.allSettled Basic ===');

  const results = await Promise.allSettled([
    fetchData('user', 100),
    fetchData('posts', 50, true), // Fails
    fetchData('comments', 150),
  ]);

  results.forEach((result, i) => {
    if (result.status === 'fulfilled') {
      console.log(`Promise ${i}: Success -`, result.value);
    } else {
      console.log(`Promise ${i}: Failed -`, result.reason.message);
    }
  });
}

// promiseAllSettledBasic();

// --------------------------------------------
// 6. Promise.allSettled() - Extracting Results
// --------------------------------------------

async function extractSettledResults() {
  console.log('\n=== Extract Settled Results ===');

  const results = await Promise.allSettled([
    Promise.resolve(1),
    Promise.reject(new Error('Failed')),
    Promise.resolve(3),
  ]);

  // Get only successful results
  const successes = results
    .filter((r) => r.status === 'fulfilled')
    .map((r) => r.value);

  // Get only failures
  const failures = results
    .filter((r) => r.status === 'rejected')
    .map((r) => r.reason);

  console.log('Successes:', successes); // [1, 3]
  console.log('Failures:', failures); // [Error: Failed]
}

// extractSettledResults();

// --------------------------------------------
// 7. Promise.allSettled() - Partial Success
// --------------------------------------------

async function partialSuccessHandling() {
  console.log('\n=== Partial Success Handling ===');

  async function fetchWithFallback(urls) {
    const results = await Promise.allSettled(
      urls.map((url) =>
        delay(Math.random() * 200).then(() => {
          if (Math.random() > 0.5) throw new Error(`Failed: ${url}`);
          return { url, data: 'content' };
        })
      )
    );

    const successful = results
      .filter((r) => r.status === 'fulfilled')
      .map((r) => r.value);

    const failed = results
      .filter((r) => r.status === 'rejected')
      .map((r) => r.reason.message);

    return { successful, failed };
  }

  const { successful, failed } = await fetchWithFallback([
    '/api/1',
    '/api/2',
    '/api/3',
    '/api/4',
  ]);

  console.log('Loaded:', successful.length, 'items');
  console.log('Failed:', failed.length, 'items');
}

// partialSuccessHandling();

// --------------------------------------------
// 8. Promise.race() - Basic Usage
// --------------------------------------------

async function promiseRaceBasic() {
  console.log('\n=== Promise.race Basic ===');

  const result = await Promise.race([
    delay(300).then(() => 'slow'),
    delay(100).then(() => 'fast'),
    delay(200).then(() => 'medium'),
  ]);

  console.log('Winner:', result); // 'fast'
}

// promiseRaceBasic();

// --------------------------------------------
// 9. Promise.race() - Timeout Pattern
// --------------------------------------------

async function timeoutPattern() {
  console.log('\n=== Timeout Pattern ===');

  function timeout(ms) {
    return new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Timeout!')), ms)
    );
  }

  async function fetchWithTimeout(fetchPromise, ms) {
    return Promise.race([fetchPromise, timeout(ms)]);
  }

  try {
    // Fast operation - succeeds
    const fast = await fetchWithTimeout(
      delay(100).then(() => 'Fast result'),
      500
    );
    console.log('Fast:', fast);

    // Slow operation - times out
    const slow = await fetchWithTimeout(
      delay(1000).then(() => 'Slow result'),
      500
    );
    console.log('Slow:', slow);
  } catch (error) {
    console.log('Error:', error.message); // 'Timeout!'
  }
}

// timeoutPattern();

// --------------------------------------------
// 10. Promise.race() - First Response from Multiple Servers
// --------------------------------------------

async function fastestServer() {
  console.log('\n=== Fastest Server ===');

  function fetchFromServer(server, latency) {
    return delay(latency).then(() => ({
      server,
      data: 'Response data',
      latency,
    }));
  }

  const result = await Promise.race([
    fetchFromServer('server-us', 150),
    fetchFromServer('server-eu', 80),
    fetchFromServer('server-asia', 200),
  ]);

  console.log(`Fastest: ${result.server} (${result.latency}ms)`);
}

// fastestServer();

// --------------------------------------------
// 11. Promise.any() - Basic Usage
// --------------------------------------------

async function promiseAnyBasic() {
  console.log('\n=== Promise.any Basic ===');

  const result = await Promise.any([
    delay(300).then(() => 'slow'),
    delay(100).then(() => 'fast'),
    delay(200).then(() => 'medium'),
  ]);

  console.log('First to fulfill:', result); // 'fast'
}

// promiseAnyBasic();

// --------------------------------------------
// 12. Promise.any() - Ignores Rejections
// --------------------------------------------

async function promiseAnyIgnoresRejections() {
  console.log('\n=== Promise.any Ignores Rejections ===');

  const result = await Promise.any([
    Promise.reject(new Error('Error 1')),
    delay(200).then(() => 'Success!'),
    Promise.reject(new Error('Error 2')),
  ]);

  console.log('Result:', result); // 'Success!'
  // Rejections are ignored if at least one fulfills
}

// promiseAnyIgnoresRejections();

// --------------------------------------------
// 13. Promise.any() - All Reject = AggregateError
// --------------------------------------------

async function promiseAnyAllReject() {
  console.log('\n=== Promise.any All Reject ===');

  try {
    await Promise.any([
      Promise.reject(new Error('Error 1')),
      Promise.reject(new Error('Error 2')),
      Promise.reject(new Error('Error 3')),
    ]);
  } catch (error) {
    console.log('Error type:', error.constructor.name); // AggregateError
    console.log(
      'Errors:',
      error.errors.map((e) => e.message)
    );
    // ['Error 1', 'Error 2', 'Error 3']
  }
}

// promiseAnyAllReject();

// --------------------------------------------
// 14. Promise.any() - Fallback Sources
// --------------------------------------------

async function fallbackSources() {
  console.log('\n=== Fallback Sources ===');

  async function fetchFromCDN(cdn) {
    await delay(Math.random() * 100);
    if (cdn === 'cdn1') throw new Error('CDN1 down');
    return { cdn, content: 'Resource content' };
  }

  try {
    const result = await Promise.any([
      fetchFromCDN('cdn1'), // Will fail
      fetchFromCDN('cdn2'),
      fetchFromCDN('cdn3'),
    ]);
    console.log(`Got content from ${result.cdn}`);
  } catch (error) {
    console.log('All CDNs failed');
  }
}

// fallbackSources();

// --------------------------------------------
// 15. Combining Combinators
// --------------------------------------------

async function combinedExample() {
  console.log('\n=== Combined Example ===');

  // Fetch from multiple endpoints, timeout each, get results for all
  async function fetchWithTimeout(url, ms) {
    const timeout = delay(ms).then(() => {
      throw new Error(`Timeout: ${url}`);
    });
    const fetch = delay(Math.random() * 200).then(() => ({
      url,
      data: 'content',
    }));
    return Promise.race([fetch, timeout]);
  }

  const urls = ['/api/a', '/api/b', '/api/c', '/api/d'];

  // Use allSettled to handle partial failures with timeout
  const results = await Promise.allSettled(
    urls.map((url) => fetchWithTimeout(url, 100))
  );

  const succeeded = results.filter((r) => r.status === 'fulfilled');
  const failed = results.filter((r) => r.status === 'rejected');

  console.log(`Succeeded: ${succeeded.length}, Failed: ${failed.length}`);
}

// combinedExample();

// --------------------------------------------
// Run Examples
// --------------------------------------------

async function runAll() {
  await promiseAllBasic();
  await promiseAllOrder();
  await promiseAllFailure();
  await fetchMultipleAPIs();
  await promiseAllSettledBasic();
  await extractSettledResults();
  await promiseRaceBasic();
  await timeoutPattern();
  await promiseAnyBasic();
  await promiseAnyIgnoresRejections();
  await promiseAnyAllReject();
  await combinedExample();
}

// Uncomment to run all examples:
// runAll();

console.log('Promise Combinators Examples - Uncomment runAll() to execute');
Examples - JavaScript Tutorial | DeepML