Learn async/await syntax for cleaner asynchronous code, error handling, and parallel execution patterns.
Async/await is syntactic sugar built on top of Promises that revolutionized how we write asynchronous JavaScript. Introduced in ES2017 (ES8), async/await allows you to write asynchronous code that looks and behaves like synchronous code, eliminating callback hell and making Promise chains more readable and maintainable.
The async keyword creates an asynchronous function that always returns a Promise, while the await keyword pauses execution until a Promise resolves, making asynchronous operations feel synchronous. This combination provides the best of both worlds: the power of Promises with the readability of synchronous code.
Understanding async/await is crucial for modern JavaScript development, as it's become the preferred way to handle asynchronous operations in most codebases. It's widely used in Node.js applications, modern web APIs, and frontend frameworks like React, Vue, and Angular for handling everything from API calls to database operations.
Async functions are declared using the async keyword and automatically return a Promise. They provide a foundation for using await and handling asynchronous operations with clean syntax.
Basic Async Function Declaration:
1// Regular function declaration with async
2async function fetchUserData() {
3 return "User data fetched!";
4}
5
6// Arrow function with async
7const fetchUserDataArrow = async () => {
8 return "User data fetched!";
9};
10
11// Method in object with async
12const userService = {
13 async getUser(id) {
14 return `User ${id} data`;
15 }
16};
17
18// Method in class with async
19class UserManager {
20 async fetchAllUsers() {
21 return ["user1", "user2", "user3"];
22 }
23
24 async getUserById(id) {
25 return { id, name: `User ${id}` };
26 }
27}
28
29console.log(fetchUserData()); // Returns Promise<string>
30console.log(fetchUserData() instanceof Promise); // true
31
32// Async functions automatically wrap return values in Promises
33fetchUserData().then(result => {
34 console.log(result); // "User data fetched!"
35});Async Function Behavior:
1// Async functions always return Promises
2async function returnString() {
3 return "Hello World"; // Automatically wrapped in Promise.resolve()
4}
5
6async function returnPromise() {
7 return Promise.resolve("Explicit Promise");
8}
9
10async function returnRejection() {
11 throw new Error("Something went wrong"); // Becomes Promise.reject()
12}
13
14// Test the behavior
15returnString().then(result => {
16 console.log("String result:", result); // "Hello World"
17});
18
19returnPromise().then(result => {
20 console.log("Promise result:", result); // "Explicit Promise"
21});
22
23returnRejection().catch(error => {
24 console.log("Error caught:", error.message); // "Something went wrong"
25});Async Function vs Regular Function:
1// Regular function returning Promise
2function regularAsyncFunction() {
3 return new Promise((resolve, reject) => {
4 setTimeout(() => {
5 resolve("Regular async result");
6 }, 1000);
7 });
8}
9
10// Equivalent async function
11async function modernAsyncFunction() {
12 // We'll use await with Promises inside
13 return new Promise(resolve => {
14 setTimeout(() => {
15 resolve("Modern async result");
16 }, 1000);
17 });
18}
19
20// Both functions work the same way
21regularAsyncFunction().then(result => console.log(result));
22modernAsyncFunction().then(result => console.log(result));
23
24// But async functions provide cleaner syntax for complex operations
25async function complexOperation() {
26 const step1 = await fetch('/api/step1').then(r => r.json());
27 const step2 = await fetch(`/api/step2/${step1.id}`).then(r => r.json());
28 const step3 = await fetch(`/api/step3/${step2.id}`).then(r => r.json());
29
30 return {
31 step1,
32 step2,
33 step3,
34 completed: true
35 };
36}Error Handling in Async Functions:
1// Errors in async functions become rejected Promises
2async function riskyOperation() {
3 if (Math.random() < 0.5) {
4 throw new Error("Random failure occurred");
5 }
6 return "Operation successful";
7}
8
9// Handle errors with try/catch or Promise.catch()
10async function handleAsyncErrors() {
11 try {
12 const result = await riskyOperation();
13 console.log("Success:", result);
14 return result;
15 } catch (error) {
16 console.error("Error caught:", error.message);
17 throw error; // Re-throw or handle gracefully
18 }
19}
20
21// Or handle with Promise methods
22riskyOperation()
23 .then(result => console.log("Promise success:", result))
24 .catch(error => console.error("Promise error:", error.message));
25
26// Async functions can also use finally-like cleanup
27async function operationWithCleanup() {
28 let resource = null;
29 try {
30 resource = await acquireResource();
31 const result = await performOperation(resource);
32 return result;
33 } catch (error) {
34 console.error("Operation failed:", error);
35 throw error;
36 } finally {
37 if (resource) {
38 await releaseResource(resource);
39 }
40 }
41}
42
43// Helper functions for example
44async function acquireResource() {
45 return { id: 'resource_1', type: 'database_connection' };
46}
47
48async function performOperation(resource) {
49 return `Operation completed with ${resource.type}`;
50}
51
52async function releaseResource(resource) {
53 console.log(`Released resource: ${resource.id}`);
54}Async functions provide the foundation for modern asynchronous JavaScript, offering clean syntax and automatic Promise handling.
The await keyword can only be used inside async functions and pauses execution until a Promise resolves or rejects. It makes asynchronous code read like synchronous code while maintaining non-blocking behavior.
Basic Await Usage:
1// Simulated async operations
2function delay(ms) {
3 return new Promise(resolve => setTimeout(resolve, ms));
4}
5
6function fetchData(endpoint) {
7 return new Promise((resolve, reject) => {
8 setTimeout(() => {
9 if (endpoint.includes('error')) {
10 reject(new Error(`Failed to fetch from ${endpoint}`));
11 } else {
12 resolve(`Data from ${endpoint}`);
13 }
14 }, Math.random() * 1000 + 500);
15 });
16}
17
18// Using await to pause execution
19async function demonstrateAwait() {
20 console.log("Starting operations...");
21
22 // Await pauses until Promise resolves
23 console.log("Fetching user data...");
24 const userData = await fetchData('/api/users');
25 console.log("User data received:", userData);
26
27 // Sequential operations with await
28 console.log("Fetching posts...");
29 const postsData = await fetchData('/api/posts');
30 console.log("Posts data received:", postsData);
31
32 // Can use await with any Promise
33 console.log("Waiting 1 second...");
34 await delay(1000);
35 console.log("Wait complete!");
36
37 return {
38 user: userData,
39 posts: postsData,
40 timestamp: new Date()
41 };
42}
43
44// Execute the async function
45demonstrateAwait()
46 .then(result => {
47 console.log("Final result:", result);
48 })
49 .catch(error => {
50 console.error("Error occurred:", error.message);
51 });Await vs Promise Chains:
1// Traditional Promise chain approach
2function traditionalPromiseChain() {
3 return fetchData('/api/user')
4 .then(user => {
5 console.log("Got user:", user);
6 return fetchData(`/api/user/${user.id}/profile`);
7 })
8 .then(profile => {
9 console.log("Got profile:", profile);
10 return fetchData(`/api/user/${profile.userId}/posts`);
11 })
12 .then(posts => {
13 console.log("Got posts:", posts);
14 return {
15 user: posts.user,
16 profile: posts.profile,
17 posts: posts.data
18 };
19 })
20 .catch(error => {
21 console.error("Chain error:", error);
22 throw error;
23 });
24}
25
26// Modern async/await approach
27async function modernAsyncAwait() {
28 try {
29 console.log("Fetching user...");
30 const user = await fetchData('/api/user');
31 console.log("Got user:", user);
32
33 console.log("Fetching profile...");
34 const profile = await fetchData(`/api/user/123/profile`);
35 console.log("Got profile:", profile);
36
37 console.log("Fetching posts...");
38 const posts = await fetchData(`/api/user/123/posts`);
39 console.log("Got posts:", posts);
40
41 return {
42 user,
43 profile,
44 posts,
45 fetchedAt: new Date()
46 };
47 } catch (error) {
48 console.error("Async/await error:", error);
49 throw error;
50 }
51}
52
53// Both approaches work identically but async/await is more readableConditional and Loop Usage with Await:
1// Conditional await operations
2async function conditionalFetch(userType) {
3 const baseData = await fetchData('/api/base');
4
5 if (userType === 'premium') {
6 const premiumData = await fetchData('/api/premium');
7 return { ...baseData, premium: premiumData };
8 } else if (userType === 'admin') {
9 const adminData = await fetchData('/api/admin');
10 return { ...baseData, admin: adminData };
11 }
12
13 return baseData;
14}
15
16// Sequential processing with loops
17async function processItemsSequentially(items) {
18 const results = [];
19
20 for (const item of items) {
21 console.log(`Processing item: ${item}`);
22 const result = await fetchData(`/api/process/${item}`);
23 results.push(result);
24
25 // Add delay between requests to avoid overwhelming server
26 await delay(100);
27 }
28
29 return results;
30}
31
32// Error handling in loops
33async function processWithErrorHandling(items) {
34 const results = [];
35 const errors = [];
36
37 for (const item of items) {
38 try {
39 const result = await fetchData(`/api/process/${item}`);
40 results.push({ item, result, status: 'success' });
41 } catch (error) {
42 errors.push({ item, error: error.message, status: 'failed' });
43 }
44 }
45
46 return { results, errors };
47}
48
49// Parallel processing vs sequential
50async function compareSequentialVsParallel() {
51 const items = ['item1', 'item2', 'item3'];
52
53 // Sequential - one after another (slower but controlled)
54 console.time('Sequential');
55 const sequentialResults = await processItemsSequentially(items);
56 console.timeEnd('Sequential');
57
58 // Parallel - all at once (faster but more resource intensive)
59 console.time('Parallel');
60 const parallelPromises = items.map(item => fetchData(`/api/process/${item}`));
61 const parallelResults = await Promise.all(parallelPromises);
62 console.timeEnd('Parallel');
63
64 return { sequentialResults, parallelResults };
65}Await with Different Promise States:
1// Await handling resolved Promises
2async function handleResolvedPromises() {
3 const immediateValue = await Promise.resolve("Immediate success");
4 console.log("Immediate:", immediateValue);
5
6 const delayedValue = await new Promise(resolve =>
7 setTimeout(() => resolve("Delayed success"), 1000)
8 );
9 console.log("Delayed:", delayedValue);
10}
11
12// Await with rejected Promises (requires try/catch)
13async function handleRejectedPromises() {
14 try {
15 const rejectedValue = await Promise.reject(new Error("Promise rejected"));
16 console.log("This won't execute");
17 } catch (error) {
18 console.error("Caught rejection:", error.message);
19 }
20
21 // Execution continues after catch
22 console.log("Continuing after error handling");
23}
24
25// Await with timeout
26async function awaitWithTimeout(promise, timeoutMs) {
27 const timeoutPromise = new Promise((_, reject) => {
28 setTimeout(() => reject(new Error(`Timeout after ${timeoutMs}ms`)), timeoutMs);
29 });
30
31 try {
32 const result = await Promise.race([promise, timeoutPromise]);
33 return result;
34 } catch (error) {
35 if (error.message.includes('Timeout')) {
36 console.error("Operation timed out");
37 }
38 throw error;
39 }
40}
41
42// Usage examples
43handleResolvedPromises();
44handleRejectedPromises();
45
46// Test timeout
47const slowPromise = new Promise(resolve =>
48 setTimeout(() => resolve("Slow response"), 3000)
49);
50
51awaitWithTimeout(slowPromise, 2000)
52 .catch(error => console.error("Timeout error:", error.message));The await keyword transforms Promise-based asynchronous code into readable, linear code that's easier to understand and maintain.
Error handling in async/await uses familiar try/catch syntax, making it much more intuitive than Promise .catch() chains. This approach provides better error context and makes debugging easier.
Basic Try/Catch with Async/Await:
1// Simple error handling
2async function basicErrorHandling() {
3 try {
4 const data = await fetchRiskyData();
5 console.log("Success:", data);
6 return data;
7 } catch (error) {
8 console.error("Error caught:", error.message);
9 throw error; // Re-throw or handle gracefully
10 }
11}
12
13// Simulated risky operation
14async function fetchRiskyData() {
15 const success = Math.random() > 0.5;
16 await delay(500);
17
18 if (success) {
19 return { data: "Successfully fetched!", timestamp: new Date() };
20 } else {
21 throw new Error("Random failure occurred");
22 }
23}
24
25// Multiple operations with single try/catch
26async function multipleOperationsWithSingleCatch() {
27 try {
28 const user = await fetchData('/api/user');
29 const profile = await fetchData('/api/profile');
30 const settings = await fetchData('/api/settings');
31
32 return { user, profile, settings };
33 } catch (error) {
34 // Any failure in the chain is caught here
35 console.error("One of the operations failed:", error.message);
36
37 // Determine which operation failed based on error
38 if (error.message.includes('user')) {
39 console.log("User fetch failed - using guest mode");
40 return { user: null, profile: null, settings: defaultSettings() };
41 }
42
43 throw error;
44 }
45}
46
47function defaultSettings() {
48 return { theme: 'light', notifications: true };
49}Granular Error Handling:
1// Handle different operations separately
2async function granularErrorHandling() {
3 let user, profile, settings;
4
5 // Handle user fetch
6 try {
7 user = await fetchData('/api/user');
8 console.log("User fetched successfully");
9 } catch (error) {
10 console.error("User fetch failed:", error.message);
11 user = { id: 'guest', name: 'Guest User' };
12 }
13
14 // Handle profile fetch (only if user exists)
15 if (user && user.id !== 'guest') {
16 try {
17 profile = await fetchData(`/api/user/${user.id}/profile`);
18 console.log("Profile fetched successfully");
19 } catch (error) {
20 console.error("Profile fetch failed:", error.message);
21 profile = { bio: 'No profile available' };
22 }
23 }
24
25 // Handle settings fetch with retry
26 let retries = 3;
27 while (retries > 0) {
28 try {
29 settings = await fetchData('/api/settings');
30 console.log("Settings fetched successfully");
31 break;
32 } catch (error) {
33 retries--;
34 console.error(`Settings fetch failed, ${retries} retries left`);
35
36 if (retries === 0) {
37 console.log("Using default settings");
38 settings = defaultSettings();
39 } else {
40 await delay(1000); // Wait before retry
41 }
42 }
43 }
44
45 return { user, profile, settings };
46}Error Recovery Patterns:
1// Error recovery with fallback services
2async function fetchWithFallbacks(endpoint) {
3 const services = [
4 `https://api1.example.com${endpoint}`,
5 `https://api2.example.com${endpoint}`,
6 `https://cache.example.com${endpoint}`
7 ];
8
9 for (let i = 0; i < services.length; i++) {
10 try {
11 console.log(`Trying service ${i + 1}: ${services[i]}`);
12 const data = await fetchData(services[i]);
13 console.log(`Service ${i + 1} succeeded`);
14 return { data, source: `service_${i + 1}` };
15 } catch (error) {
16 console.error(`Service ${i + 1} failed:, error.message`);
17
18 if (i === services.length - 1) {
19 // All services failed
20 throw new Error('All services unavailable');
21 }
22
23 // Wait before trying next service
24 await delay(500);
25 }
26 }
27}
28
29// Partial failure handling
30async function processMultipleItemsWithRecovery(items) {
31 const results = [];
32 const failures = [];
33
34 for (const item of items) {
35 try {
36 const processed = await processItem(item);
37 results.push({ item, result: processed, status: 'success' });
38 } catch (error) {
39 console.error(`Failed to process ${item}:, error.message`);
40 failures.push({ item, error: error.message, status: 'failed' });
41
42 // Try recovery strategy
43 try {
44 const recovered = await recoverItem(item);
45 results.push({ item, result: recovered, status: 'recovered' });
46 } catch (recoveryError) {
47 console.error(`Recovery also failed for ${item}`);
48 }
49 }
50 }
51
52 return {
53 successful: results.filter(r => r.status === 'success'),
54 recovered: results.filter(r => r.status === 'recovered'),
55 failed: failures
56 };
57}
58
59async function processItem(item) {
60 // Simulate processing that might fail
61 await delay(200);
62 if (item.includes('bad')) {
63 throw new Error(`Cannot process ${item}`);
64 }
65 return `Processed: ${item}`;
66}
67
68async function recoverItem(item) {
69 // Simulation of recovery strategy
70 await delay(100);
71 if (Math.random() > 0.5) {
72 return `Recovered: ${item} (simplified)`;
73 }
74 throw new Error('Recovery failed');
75}Advanced Error Handling Patterns:
1// Custom error types for better error handling
2class ValidationError extends Error {
3 constructor(message, field) {
4 super(message);
5 this.name = 'ValidationError';
6 this.field = field;
7 }
8}
9
10class NetworkError extends Error {
11 constructor(message, statusCode) {
12 super(message);
13 this.name = 'NetworkError';
14 this.statusCode = statusCode;
15 }
16}
17
18class BusinessLogicError extends Error {
19 constructor(message, code) {
20 super(message);
21 this.name = 'BusinessLogicError';
22 this.code = code;
23 }
24}
25
26// Function that throws different error types
27async function complexOperation(userData) {
28 try {
29 // Validation phase
30 if (!userData.email) {
31 throw new ValidationError('Email is required', 'email');
32 }
33
34 // Network operation
35 const response = await fetchData('/api/validate');
36 if (!response) {
37 throw new NetworkError('Service unavailable', 503);
38 }
39
40 // Business logic
41 if (userData.age < 18) {
42 throw new BusinessLogicError('User must be 18 or older', 'AGE_RESTRICTION');
43 }
44
45 return await processValidUser(userData);
46
47 } catch (error) {
48 // Handle different error types appropriately
49 if (error instanceof ValidationError) {
50 console.error(`Validation failed for field '${error.field}': ${error.message}`);
51 return { success: false, error: 'validation', field: error.field };
52 } else if (error instanceof NetworkError) {
53 console.error(`Network error (${error.statusCode}): ${error.message}`);
54 return { success: false, error: 'network', retryable: true };
55 } else if (error instanceof BusinessLogicError) {
56 console.error(`Business rule violation (${error.code}): ${error.message}`);
57 return { success: false, error: 'business', code: error.code };
58 } else {
59 // Unexpected error
60 console.error('Unexpected error:', error);
61 throw error;
62 }
63 }
64}
65
66async function processValidUser(userData) {
67 await delay(300);
68 return { success: true, userId: Math.floor(Math.random() * 1000), userData };
69}
70
71// Error boundary pattern for async operations
72class AsyncErrorBoundary {
73 static async execute(operation, errorHandler) {
74 try {
75 return await operation();
76 } catch (error) {
77 if (errorHandler) {
78 return await errorHandler(error);
79 }
80 throw error;
81 }
82 }
83
84 static async executeWithRetry(operation, maxRetries = 3, delay = 1000) {
85 for (let attempt = 1; attempt <= maxRetries; attempt++) {
86 try {
87 return await operation();
88 } catch (error) {
89 if (attempt === maxRetries) {
90 throw new Error(`Operation failed after ${maxRetries} attempts: ${error.message}`);
91 }
92
93 console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
94 await new Promise(resolve => setTimeout(resolve, delay));
95 delay *= 2; // Exponential backoff
96 }
97 }
98 }
99}
100
101// Usage examples
102const testUserData = [
103 { name: 'Alice', email: '[email protected]', age: 25 },
104 { name: 'Bob', age: 30 }, // Missing email
105 { name: 'Charlie', email: '[email protected]', age: 16 }, // Too young
106];
107
108testUserData.forEach(async (userData, index) => {
109 try {
110 const result = await complexOperation(userData);
111 console.log(`User ${index + 1} result:, result`);
112 } catch (error) {
113 console.error(`Unhandled error for user ${index + 1}:, error.message`);
114 }
115});
116
117// Using error boundary
118AsyncErrorBoundary.execute(
119 () => complexOperation(testUserData[0]),
120 (error) => {
121 console.log("Error handled by boundary:", error.message);
122 return { success: false, handledBy: 'error-boundary' };
123 }
124).then(result => {
125 console.log("Boundary result:", result);
126});Try/catch with async/await provides powerful, intuitive error handling that makes asynchronous code as manageable as synchronous code.
Advanced async/await patterns help you handle complex asynchronous workflows efficiently. These patterns address common challenges like parallel processing, conditional flows, and sophisticated error recovery.
Parallel vs Sequential Execution:
1// Sequential execution - operations run one after another
2async function sequentialExecution() {
3 console.time('Sequential');
4
5 const result1 = await fetchData('/api/endpoint1'); // Wait for this
6 const result2 = await fetchData('/api/endpoint2'); // Then wait for this
7 const result3 = await fetchData('/api/endpoint3'); // Finally wait for this
8
9 console.timeEnd('Sequential');
10 return [result1, result2, result3];
11}
12
13// Parallel execution - operations start simultaneously
14async function parallelExecution() {
15 console.time('Parallel');
16
17 // Start all operations immediately
18 const promise1 = fetchData('/api/endpoint1');
19 const promise2 = fetchData('/api/endpoint2');
20 const promise3 = fetchData('/api/endpoint3');
21
22 // Wait for all to complete
23 const results = await Promise.all([promise1, promise2, promise3]);
24
25 console.timeEnd('Parallel');
26 return results;
27}
28
29// Hybrid approach - some sequential, some parallel
30async function hybridExecution() {
31 console.time('Hybrid');
32
33 // First, get user data (required for next steps)
34 const user = await fetchData('/api/user');
35
36 // Then fetch profile and posts in parallel (both need user.id)
37 const [profile, posts, friends] = await Promise.all([
38 fetchData(`/api/user/${user.id}/profile`),
39 fetchData(`/api/user/${user.id}/posts`),
40 fetchData(`/api/user/${user.id}/friends`)
41 ]);
42
43 console.timeEnd('Hybrid');
44 return { user, profile, posts, friends };
45}
46
47// Demonstrate the performance difference
48async function compareExecutionMethods() {
49 console.log("Comparing execution methods...");
50
51 await sequentialExecution(); // ~3 seconds total
52 await parallelExecution(); // ~1 second total (max of individual times)
53 await hybridExecution(); // ~2 seconds total
54}Conditional Async Flows:
1// Complex conditional async workflows
2async function conditionalAsyncFlow(userType, permissions) {
3 let userData, additionalData;
4
5 // Base user data (always needed)
6 userData = await fetchData('/api/user/base');
7
8 // Conditional data fetching based on user type
9 switch (userType) {
10 case 'admin':
11 const [adminTools, systemStats, userList] = await Promise.all([
12 fetchData('/api/admin/tools'),
13 fetchData('/api/admin/stats'),
14 permissions.includes('view_users') ?
15 fetchData('/api/admin/users') :
16 Promise.resolve(null)
17 ]);
18 additionalData = { adminTools, systemStats, userList };
19 break;
20
21 case 'premium':
22 const [premiumFeatures, analytics] = await Promise.all([
23 fetchData('/api/premium/features'),
24 permissions.includes('analytics') ?
25 fetchData('/api/premium/analytics') :
26 Promise.resolve(null)
27 ]);
28 additionalData = { premiumFeatures, analytics };
29 break;
30
31 case 'basic':
32 additionalData = await fetchData('/api/basic/features');
33 break;
34
35 default:
36 additionalData = null;
37 }
38
39 return { userData, additionalData, userType };
40}
41
42// Async operations with dynamic dependencies
43async function dynamicDependencyFlow(config) {
44 const results = {};
45
46 // Always fetch base configuration
47 results.config = await fetchData('/api/config');
48
49 // Determine what else to fetch based on config
50 const requiredServices = results.config.enabledServices || [];
51 const fetchPromises = [];
52
53 if (requiredServices.includes('analytics')) {
54 fetchPromises.push(
55 fetchData('/api/analytics').then(data => {
56 results.analytics = data;
57 })
58 );
59 }
60
61 if (requiredServices.includes('notifications')) {
62 fetchPromises.push(
63 fetchData('/api/notifications').then(data => {
64 results.notifications = data;
65 })
66 );
67 }
68
69 if (requiredServices.includes('social')) {
70 fetchPromises.push(
71 fetchData('/api/social').then(data => {
72 results.social = data;
73 })
74 );
75 }
76
77 // Wait for all dynamic fetches to complete
78 await Promise.all(fetchPromises);
79
80 return results;
81}Async Iteration Patterns:
1// Sequential processing with for...of
2async function processItemsSequentially(items) {
3 const results = [];
4
5 for (const item of items) {
6 try {
7 console.log(`Processing ${item}...`);
8 const result = await processItem(item);
9 results.push({ item, result, status: 'success' });
10
11 // Optional delay between items
12 await delay(100);
13 } catch (error) {
14 results.push({ item, error: error.message, status: 'error' });
15 }
16 }
17
18 return results;
19}
20
21// Batch processing with controlled concurrency
22async function processBatches(items, batchSize = 3) {
23 const results = [];
24
25 for (let i = 0; i < items.length; i += batchSize) {
26 const batch = items.slice(i, i + batchSize);
27 console.log(`Processing batch ${Math.floor(i / batchSize) + 1}: ${batch.join(', ')}`);
28
29 const batchPromises = batch.map(async (item) => {
30 try {
31 const result = await processItem(item);
32 return { item, result, status: 'success' };
33 } catch (error) {
34 return { item, error: error.message, status: 'error' };
35 }
36 });
37
38 const batchResults = await Promise.all(batchPromises);
39 results.push(...batchResults);
40
41 // Optional delay between batches
42 if (i + batchSize < items.length) {
43 await delay(500);
44 }
45 }
46
47 return results;
48}
49
50// Async reduce pattern
51async function asyncReduce(items, reducer, initialValue) {
52 let accumulator = initialValue;
53
54 for (const item of items) {
55 accumulator = await reducer(accumulator, item);
56 }
57
58 return accumulator;
59}
60
61// Example: calculate total value from async operations
62async function calculateTotalValue(items) {
63 return await asyncReduce(items, async (total, item) => {
64 const value = await fetchItemValue(item);
65 return total + value;
66 }, 0);
67}
68
69async function fetchItemValue(item) {
70 await delay(100);
71 return Math.floor(Math.random() * 100) + 1;
72}Advanced Error Recovery:
1// Circuit breaker pattern with async/await
2class AsyncCircuitBreaker {
3 constructor(threshold = 5, timeout = 60000, monitoringPeriod = 10000) {
4 this.threshold = threshold;
5 this.timeout = timeout;
6 this.monitoringPeriod = monitoringPeriod;
7 this.failureCount = 0;
8 this.lastFailureTime = null;
9 this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
10 }
11
12 async execute(operation) {
13 if (this.state === 'OPEN') {
14 if (Date.now() - this.lastFailureTime < this.timeout) {
15 throw new Error('Circuit breaker is OPEN');
16 } else {
17 this.state = 'HALF_OPEN';
18 }
19 }
20
21 try {
22 const result = await operation();
23 this.onSuccess();
24 return result;
25 } catch (error) {
26 this.onFailure();
27 throw error;
28 }
29 }
30
31 onSuccess() {
32 this.failureCount = 0;
33 this.state = 'CLOSED';
34 }
35
36 onFailure() {
37 this.failureCount++;
38 this.lastFailureTime = Date.now();
39
40 if (this.failureCount >= this.threshold) {
41 this.state = 'OPEN';
42 }
43 }
44}
45
46// Exponential backoff retry with jitter
47async function retryWithBackoff(operation, maxRetries = 5, baseDelay = 1000) {
48 for (let attempt = 1; attempt <= maxRetries; attempt++) {
49 try {
50 return await operation();
51 } catch (error) {
52 if (attempt === maxRetries) {
53 throw new Error(`Failed after ${maxRetries} attempts: ${error.message}`);
54 }
55
56 // Exponential backoff with jitter
57 const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);
58 const jitter = Math.random() * 0.1 * exponentialDelay;
59 const totalDelay = exponentialDelay + jitter;
60
61 console.log(`Attempt ${attempt} failed, retrying in ${Math.round(totalDelay)}ms...`);
62 await delay(totalDelay);
63 }
64 }
65}
66
67// Graceful degradation pattern
68async function fetchWithGracefulDegradation(endpoint, fallbackStrategies = []) {
69 try {
70 return await fetchData(endpoint);
71 } catch (primaryError) {
72 console.warn(`Primary endpoint failed: ${primaryError.message}`);
73
74 for (let i = 0; i < fallbackStrategies.length; i++) {
75 try {
76 console.log(`Trying fallback strategy ${i + 1}...`);
77 const result = await fallbackStrategies[i]();
78 console.log(`Fallback strategy ${i + 1} succeeded`);
79 return { data: result, source: `fallback_${i + 1}` };
80 } catch (fallbackError) {
81 console.warn(`Fallback ${i + 1} failed: ${fallbackError.message}`);
82 continue;
83 }
84 }
85
86 throw new Error('All strategies failed');
87 }
88}
89
90// Usage examples
91const circuitBreaker = new AsyncCircuitBreaker(3, 5000);
92
93async function demonstrateAdvancedPatterns() {
94 const items = ['item1', 'item2', 'item3', 'item4', 'item5'];
95
96 // Test different processing patterns
97 console.log("Sequential processing:");
98 const sequentialResults = await processItemsSequentially(items);
99 console.log(sequentialResults);
100
101 console.log("\nBatch processing:");
102 const batchResults = await processBatches(items, 2);
103 console.log(batchResults);
104
105 console.log("\nAsync reduce:");
106 const totalValue = await calculateTotalValue(items);
107 console.log("Total value:", totalValue);
108
109 // Test circuit breaker
110 console.log("\nCircuit breaker test:");
111 for (let i = 0; i < 8; i++) {
112 try {
113 await circuitBreaker.execute(async () => {
114 if (Math.random() < 0.7) throw new Error('Random failure');
115 return 'Success!';
116 });
117 console.log(`Operation ${i + 1}: Success`);
118 } catch (error) {
119 console.log(`Operation ${i + 1}: ${error.message}`);
120 }
121 }
122
123 // Test graceful degradation
124 console.log("\nGraceful degradation:");
125 try {
126 const result = await fetchWithGracefulDegradation('/api/unreliable', [
127 () => fetchData('/api/backup'),
128 () => Promise.resolve('Cached data'),
129 () => Promise.resolve('Static fallback')
130 ]);
131 console.log('Final result:', result);
132 } catch (error) {
133 console.error('All strategies failed:', error.message);
134 }
135}
136
137demonstrateAdvancedPatterns();These advanced patterns provide robust solutions for complex asynchronous workflows, ensuring your applications can handle various scenarios gracefully and efficiently.
Create a comprehensive data synchronization system for an e-commerce platform that demonstrates async/await patterns, error handling, parallel processing, and real-world async workflows.
1// === E-Commerce Data Synchronization System ===
2// Demonstrates advanced async/await patterns in a real-world scenario
3
4// Utility functions and configuration
5const CONFIG = {
6 API_BASE_URL: 'https://api.ecommerce.com',
7 BATCH_SIZE: 5,
8 MAX_RETRIES: 3,
9 CIRCUIT_BREAKER_THRESHOLD: 5,
10 SYNC_INTERVAL: 30000, // 30 seconds
11 ENDPOINTS: {
12 products: '/api/products',
13 inventory: '/api/inventory',
14 orders: '/api/orders',
15 customers: '/api/customers',
16 analytics: '/api/analytics'
17 }
18};
19
20// Simulate async operations with realistic delays and failure rates
21function simulateApiCall(endpoint, data = null, options = {}) {
22 return new Promise((resolve, reject) => {
23 const {
24 delay = Math.random() * 1000 + 300,
25 failureRate = 0.1,
26 timeout = 5000
27 } = options;
28
29 // Simulate timeout
30 const timeoutId = setTimeout(() => {
31 reject(new Error(`Request to ${endpoint} timed out`));
32 }, timeout);
33
34 setTimeout(() => {
35 clearTimeout(timeoutId);
36
37 if (Math.random() < failureRate) {
38 reject(new Error(`API call to ${endpoint} failed`));
39 } else {
40 resolve({
41 endpoint,
42 data: data || `Mock data from ${endpoint}`,
43 timestamp: new Date(),
44 requestId: Math.random().toString(36).substr(2, 9)
45 });
46 }
47 }, delay);
48 });
49}
50
51// Enhanced error classes for better error handling
52class SyncError extends Error {
53 constructor(message, type, endpoint, retryable = false) {
54 super(message);
55 this.name = 'SyncError';
56 this.type = type;
57 this.endpoint = endpoint;
58 this.retryable = retryable;
59 this.timestamp = new Date();
60 }
61}
62
63class ValidationError extends SyncError {
64 constructor(message, field, endpoint) {
65 super(message, 'validation', endpoint, false);
66 this.field = field;
67 }
68}
69
70class NetworkError extends SyncError {
71 constructor(message, endpoint, statusCode) {
72 super(message, 'network', endpoint, true);
73 this.statusCode = statusCode;
74 }
75}
76
77// Circuit breaker for API resilience
78class CircuitBreaker {
79 constructor(threshold = 5, timeout = 60000) {
80 this.threshold = threshold;
81 this.timeout = timeout;
82 this.failureCount = 0;
83 this.lastFailureTime = null;
84 this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
85 this.successCount = 0;
86 }
87
88 async execute(operation, endpoint) {
89 if (this.state === 'OPEN') {
90 if (Date.now() - this.lastFailureTime < this.timeout) {
91 throw new NetworkError(
92 `Circuit breaker OPEN for ${endpoint}`,
93 endpoint,
94 503
95 );
96 }
97 this.state = 'HALF_OPEN';
98 this.successCount = 0;
99 }
100
101 try {
102 const result = await operation();
103 this.onSuccess();
104 return result;
105 } catch (error) {
106 this.onFailure();
107 throw error;
108 }
109 }
110
111 onSuccess() {
112 if (this.state === 'HALF_OPEN') {
113 this.successCount++;
114 if (this.successCount >= 3) {
115 this.state = 'CLOSED';
116 this.failureCount = 0;
117 }
118 } else {
119 this.failureCount = Math.max(0, this.failureCount - 1);
120 }
121 }
122
123 onFailure() {
124 this.failureCount++;
125 this.lastFailureTime = Date.now();
126
127 if (this.failureCount >= this.threshold) {
128 this.state = 'OPEN';
129 console.warn(`Circuit breaker opened after ${this.failureCount} failures`);
130 }
131 }
132
133 getState() {
134 return {
135 state: this.state,
136 failureCount: this.failureCount,
137 lastFailureTime: this.lastFailureTime
138 };
139 }
140}
141
142// Retry mechanism with exponential backoff
143class RetryHandler {
144 static async executeWithRetry(operation, endpoint, maxRetries = 3) {
145 let lastError;
146
147 for (let attempt = 1; attempt <= maxRetries; attempt++) {
148 try {
149 return await operation();
150 } catch (error) {
151 lastError = error;
152
153 if (!error.retryable || attempt === maxRetries) {
154 break;
155 }
156
157 const delay = Math.pow(2, attempt - 1) * 1000; // Exponential backoff
158 const jitter = Math.random() * 200; // Add jitter
159 const totalDelay = delay + jitter;
160
161 console.warn(`Attempt ${attempt} failed for ${endpoint}, retrying in ${Math.round(totalDelay)}ms...`);
162 await new Promise(resolve => setTimeout(resolve, totalDelay));
163 }
164 }
165
166 throw new SyncError(
167 `Failed after ${maxRetries} attempts: ${lastError.message}`,
168 'retry_exhausted',
169 endpoint,
170 false
171 );
172 }
173}
174
175// Data synchronization manager
176class DataSyncManager {
177 constructor() {
178 this.circuitBreakers = new Map();
179 this.syncQueue = [];
180 this.isRunning = false;
181 this.syncStats = {
182 totalSyncs: 0,
183 successfulSyncs: 0,
184 failedSyncs: 0,
185 lastSyncTime: null,
186 averageSync Time: 0
187 };
188 this.syncHistory = [];
189 }
190
191 // Get or create circuit breaker for endpoint
192 getCircuitBreaker(endpoint) {
193 if (!this.circuitBreakers.has(endpoint)) {
194 this.circuitBreakers.set(endpoint, new CircuitBreaker(
195 CONFIG.CIRCUIT_BREAKER_THRESHOLD,
196 30000 // 30 second timeout
197 ));
198 }
199 return this.circuitBreakers.get(endpoint);
200 }
201
202 // Core sync operation with circuit breaker and retry
203 async performSync(endpoint, data = null, options = {}) {
204 const circuitBreaker = this.getCircuitBreaker(endpoint);
205
206 return await circuitBreaker.execute(async () => {
207 return await RetryHandler.executeWithRetry(
208 () => simulateApiCall(endpoint, data, options),
209 endpoint,
210 CONFIG.MAX_RETRIES
211 );
212 }, endpoint);
213 }
214
215 // Sync product catalog with inventory updates
216 async syncProductCatalog() {
217 console.log('šļø Starting product catalog synchronization...');
218
219 try {
220 // Fetch products and inventory in parallel
221 const [products, inventory] = await Promise.all([
222 this.performSync(CONFIG.ENDPOINTS.products),
223 this.performSync(CONFIG.ENDPOINTS.inventory)
224 ]);
225
226 console.log('ā
Products and inventory fetched successfully');
227
228 // Process products in batches to avoid overwhelming the system
229 const productList = Array.from({ length: 20 }, (_, i) => ({
230 id: `prod_${i + 1}`,
231 name: `Product ${i + 1}`,
232 price: Math.floor(Math.random() * 1000) + 10,
233 category: ['electronics', 'clothing', 'books', 'home'][Math.floor(Math.random() * 4)]
234 }));
235
236 const updatedProducts = await this.processBatches(
237 productList,
238 async (product) => {
239 // Update each product with current inventory
240 const inventoryData = await this.performSync(
241 `${CONFIG.ENDPOINTS.inventory}/${product.id}`,
242 null,
243 { delay: 200, failureRate: 0.05 }
244 );
245
246 return {
247 ...product,
248 inventory: inventoryData.data,
249 lastUpdated: new Date()
250 };
251 },
252 CONFIG.BATCH_SIZE
253 );
254
255 console.log(`ā
Updated ${updatedProducts.length} products with inventory data`);
256
257 return {
258 products: updatedProducts,
259 syncedAt: new Date(),
260 status: 'success'
261 };
262
263 } catch (error) {
264 console.error('ā Product catalog sync failed:', error.message);
265 throw error;
266 }
267 }
268
269 // Sync customer orders with payment verification
270 async syncCustomerOrders() {
271 console.log('š¦ Starting customer orders synchronization...');
272
273 try {
274 // Fetch recent orders
275 const ordersResponse = await this.performSync(
276 `${CONFIG.ENDPOINTS.orders}?recent=true`,
277 null,
278 { delay: 800, failureRate: 0.08 }
279 );
280
281 console.log('ā
Recent orders fetched');
282
283 // Simulate processing orders with different priorities
284 const orders = Array.from({ length: 15 }, (_, i) => ({
285 id: `order_${i + 1}`,
286 customerId: `cust_${Math.floor(Math.random() * 100) + 1}`,
287 amount: Math.floor(Math.random() * 5000) + 100,
288 status: ['pending', 'processing', 'shipped', 'delivered'][Math.floor(Math.random() * 4)],
289 priority: ['standard', 'express', 'overnight'][Math.floor(Math.random() * 3)]
290 }));
291
292 // Process high-priority orders first
293 const prioritizedOrders = this.prioritizeOrders(orders);
294 const processedOrders = [];
295
296 for (const order of prioritizedOrders) {
297 try {
298 // Verify payment and update order status
299 const [paymentVerification, customerData] = await Promise.all([
300 this.performSync(
301 `/api/payments/verify/${order.id}`,
302 { orderId: order.id, amount: order.amount },
303 { delay: 300, failureRate: 0.03 }
304 ),
305 this.performSync(
306 `${CONFIG.ENDPOINTS.customers}/${order.customerId}`,
307 null,
308 { delay: 200, failureRate: 0.02 }
309 )
310 ]);
311
312 processedOrders.push({
313 ...order,
314 paymentVerified: true,
315 customerData: customerData.data,
316 processedAt: new Date()
317 });
318
319 console.log(`ā
Processed order ${order.id} (${order.priority} priority)`);
320
321 } catch (error) {
322 console.warn(`ā ļø Failed to process order ${order.id}: ${error.message}`);
323 processedOrders.push({
324 ...order,
325 error: error.message,
326 processedAt: new Date()
327 });
328 }
329
330 // Small delay between orders to prevent overwhelming the system
331 await new Promise(resolve => setTimeout(resolve, 50));
332 }
333
334 console.log(`ā
Processed ${processedOrders.length} orders`);
335
336 return {
337 orders: processedOrders,
338 totalProcessed: processedOrders.length,
339 successfullyProcessed: processedOrders.filter(o => !o.error).length,
340 syncedAt: new Date(),
341 status: 'success'
342 };
343
344 } catch (error) {
345 console.error('ā Customer orders sync failed:', error.message);
346 throw error;
347 }
348 }
349
350 // Sync analytics data with error resilience
351 async syncAnalyticsData() {
352 console.log('š Starting analytics data synchronization...');
353
354 const analyticsEndpoints = [
355 { name: 'sales', endpoint: '/api/analytics/sales', critical: true },
356 { name: 'traffic', endpoint: '/api/analytics/traffic', critical: false },
357 { name: 'conversion', endpoint: '/api/analytics/conversion', critical: true },
358 { name: 'inventory_turnover', endpoint: '/api/analytics/inventory', critical: false },
359 { name: 'customer_segments', endpoint: '/api/analytics/segments', critical: false }
360 ];
361
362 const analyticsData = {};
363 const errors = [];
364
365 // Fetch critical analytics first, then non-critical in parallel
366 const criticalEndpoints = analyticsEndpoints.filter(e => e.critical);
367 const nonCriticalEndpoints = analyticsEndpoints.filter(e => !e.critical);
368
369 try {
370 // Sequential processing for critical data
371 for (const { name, endpoint } of criticalEndpoints) {
372 try {
373 console.log(`š Fetching critical analytics: ${name}`);
374 const result = await this.performSync(
375 endpoint,
376 { timeframe: '24h' },
377 { delay: 600, failureRate: 0.05 }
378 );
379 analyticsData[name] = result.data;
380 } catch (error) {
381 console.error(`ā Critical analytics failed: ${name}`);
382 errors.push({ name, error: error.message, critical: true });
383 throw error; // Fail fast for critical data
384 }
385 }
386
387 // Parallel processing for non-critical data
388 const nonCriticalPromises = nonCriticalEndpoints.map(async ({ name, endpoint }) => {
389 try {
390 console.log(`š Fetching non-critical analytics: ${name}`);
391 const result = await this.performSync(
392 endpoint,
393 { timeframe: '24h' },
394 { delay: 400, failureRate: 0.1 }
395 );
396 return { name, data: result.data };
397 } catch (error) {
398 console.warn(`ā ļø Non-critical analytics failed: ${name}`);
399 errors.push({ name, error: error.message, critical: false });
400 return { name, data: null, error: error.message };
401 }
402 });
403
404 const nonCriticalResults = await Promise.all(nonCriticalPromises);
405
406 // Merge non-critical results
407 nonCriticalResults.forEach(({ name, data }) => {
408 analyticsData[name] = data;
409 });
410
411 const successfulSyncs = Object.keys(analyticsData).filter(key => analyticsData[key] !== null).length;
412 console.log(`ā
Analytics sync completed: ${successfulSyncs}/${analyticsEndpoints.length} successful`);
413
414 return {
415 data: analyticsData,
416 errors,
417 successfulSyncs,
418 totalEndpoints: analyticsEndpoints.length,
419 syncedAt: new Date(),
420 status: errors.some(e => e.critical) ? 'partial' : 'success'
421 };
422
423 } catch (error) {
424 console.error('ā Analytics sync failed completely:', error.message);
425 throw error;
426 }
427 }
428
429 // Complete system synchronization orchestrator
430 async performCompleteSync() {
431 if (this.isRunning) {
432 console.warn('ā ļø Sync already in progress, skipping...');
433 return;
434 }
435
436 this.isRunning = true;
437 const syncStartTime = Date.now();
438
439 console.log('š Starting complete e-commerce data synchronization...');
440 console.log(`Timestamp: ${new Date().toISOString()}`);
441
442 const syncResult = {
443 startTime: new Date(),
444 endTime: null,
445 duration: null,
446 results: {},
447 errors: [],
448 status: 'in_progress'
449 };
450
451 try {
452 // Execute all sync operations with error isolation
453 const [productResult, orderResult, analyticsResult] = await Promise.allSettled([
454 this.syncProductCatalog(),
455 this.syncCustomerOrders(),
456 this.syncAnalyticsData()
457 ]);
458
459 // Process results
460 this.processSyncResults(syncResult, {
461 products: productResult,
462 orders: orderResult,
463 analytics: analyticsResult
464 });
465
466 // Update statistics
467 const syncDuration = Date.now() - syncStartTime;
468 this.updateSyncStats(syncResult, syncDuration);
469
470 console.log(`š Complete sync finished in ${Math.round(syncDuration / 1000)}s`);
471 this.printSyncSummary(syncResult);
472
473 return syncResult;
474
475 } catch (error) {
476 syncResult.status = 'failed';
477 syncResult.errors.push({
478 type: 'system',
479 message: error.message,
480 timestamp: new Date()
481 });
482
483 console.error('š„ Complete sync failed:', error.message);
484 throw error;
485
486 } finally {
487 this.isRunning = false;
488 syncResult.endTime = new Date();
489 syncResult.duration = syncResult.endTime - syncResult.startTime;
490 this.syncHistory.push(syncResult);
491
492 // Keep only last 10 sync records
493 if (this.syncHistory.length > 10) {
494 this.syncHistory = this.syncHistory.slice(-10);
495 }
496 }
497 }
498
499 // Helper methods
500 prioritizeOrders(orders) {
501 const priorityMap = { overnight: 3, express: 2, standard: 1 };
502 return orders.sort((a, b) => {
503 return priorityMap[b.priority] - priorityMap[a.priority];
504 });
505 }
506
507 async processBatches(items, processor, batchSize) {
508 const results = [];
509
510 for (let i = 0; i < items.length; i += batchSize) {
511 const batch = items.slice(i, i + batchSize);
512 console.log(`Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(items.length / batchSize)}`);
513
514 const batchPromises = batch.map(processor);
515 const batchResults = await Promise.allSettled(batchPromises);
516
517 batchResults.forEach((result, index) => {
518 if (result.status === 'fulfilled') {
519 results.push(result.value);
520 } else {
521 console.warn(`Batch item failed: ${result.reason.message}`);
522 results.push({ error: result.reason.message, item: batch[index] });
523 }
524 });
525
526 // Small delay between batches
527 if (i + batchSize < items.length) {
528 await new Promise(resolve => setTimeout(resolve, 100));
529 }
530 }
531
532 return results;
533 }
534
535 processSyncResults(syncResult, results) {
536 Object.entries(results).forEach(([key, result]) => {
537 if (result.status === 'fulfilled') {
538 syncResult.results[key] = result.value;
539 } else {
540 syncResult.results[key] = { error: result.reason.message };
541 syncResult.errors.push({
542 type: key,
543 message: result.reason.message,
544 timestamp: new Date()
545 });
546 }
547 });
548
549 const hasErrors = syncResult.errors.length > 0;
550 const hasSuccessfulResults = Object.values(syncResult.results).some(r => !r.error);
551
552 syncResult.status = hasErrors ?
553 (hasSuccessfulResults ? 'partial' : 'failed') : 'success';
554 }
555
556 updateSyncStats(syncResult, duration) {
557 this.syncStats.totalSyncs++;
558 this.syncStats.lastSyncTime = new Date();
559
560 if (syncResult.status === 'success' || syncResult.status === 'partial') {
561 this.syncStats.successfulSyncs++;
562 } else {
563 this.syncStats.failedSyncs++;
564 }
565
566 // Calculate moving average of sync times
567 const currentAverage = this.syncStats.averageSyncTime || 0;
568 this.syncStats.averageSyncTime =
569 (currentAverage * (this.syncStats.totalSyncs - 1) + duration) / this.syncStats.totalSyncs;
570 }
571
572 printSyncSummary(syncResult) {
573 console.log('\n' + '='.repeat(60));
574 console.log('š SYNC SUMMARY REPORT');
575 console.log('='.repeat(60));
576 console.log(`Status: ${syncResult.status.toUpperCase()}`);
577 console.log(`Duration: ${Math.round(syncResult.duration / 1000)}s`);
578 console.log(`Started: ${syncResult.startTime.toLocaleTimeString()}`);
579 console.log(`Ended: ${syncResult.endTime.toLocaleTimeString()}`);
580
581 console.log('\nš Results:');
582 Object.entries(syncResult.results).forEach(([key, result]) => {
583 if (result.error) {
584 console.log(` ā ${key}: FAILED - ${result.error}`);
585 } else {
586 console.log(` ā
${key}: SUCCESS`);
587 if (key === 'products' && result.products) {
588 console.log(` - ${result.products.length} products updated`);
589 } else if (key === 'orders' && result.orders) {
590 console.log(` - ${result.totalProcessed} orders processed`);
591 console.log(` - ${result.successfullyProcessed} successful`);
592 } else if (key === 'analytics' && result.data) {
593 const successful = Object.keys(result.data).filter(k => result.data[k] !== null).length;
594 console.log(` - ${successful}/${result.totalEndpoints} endpoints synced`);
595 }
596 }
597 });
598
599 if (syncResult.errors.length > 0) {
600 console.log('\nšØ Errors:');
601 syncResult.errors.forEach((error, index) => {
602 console.log(` ${index + 1}. [${error.type}] ${error.message}`);
603 });
604 }
605
606 console.log('\nš Overall Stats:');
607 console.log(` Total syncs: ${this.syncStats.totalSyncs}`);
608 console.log(` Success rate: ${((this.syncStats.successfulSyncs / this.syncStats.totalSyncs) * 100).toFixed(1)}%`);
609 console.log(` Average duration: ${Math.round(this.syncStats.averageSyncTime / 1000)}s`);
610
611 console.log('\nš§ Circuit Breaker Status:');
612 this.circuitBreakers.forEach((breaker, endpoint) => {
613 const state = breaker.getState();
614 console.log(` ${endpoint}: ${state.state} (failures: ${state.failureCount})`);
615 });
616
617 console.log('='.repeat(60) + '\n');
618 }
619
620 // Get system health report
621 getHealthReport() {
622 return {
623 isRunning: this.isRunning,
624 stats: this.syncStats,
625 circuitBreakers: Object.fromEntries(
626 Array.from(this.circuitBreakers.entries()).map(([endpoint, breaker]) => [
627 endpoint,
628 breaker.getState()
629 ])
630 ),
631 recentSyncs: this.syncHistory.slice(-5)
632 };
633 }
634}
635
636// Demonstration and testing
637async function demonstrateECommerceSync() {
638 console.log('š E-Commerce Data Synchronization System Demo');
639 console.log('===============================================\n');
640
641 const syncManager = new DataSyncManager();
642
643 try {
644 // Perform complete synchronization
645 await syncManager.performCompleteSync();
646
647 // Wait a bit and perform another sync to show circuit breaker behavior
648 console.log('\nā³ Waiting 2 seconds before next sync...');
649 await new Promise(resolve => setTimeout(resolve, 2000));
650
651 console.log('\nš Performing second sync to demonstrate resilience...');
652 await syncManager.performCompleteSync();
653
654 // Show health report
655 console.log('\nš„ System Health Report:');
656 console.log(JSON.stringify(syncManager.getHealthReport(), null, 2));
657
658 } catch (error) {
659 console.error('š„ Demo failed:', error.message);
660 }
661}
662
663// Auto-start the demonstration
664demonstrateECommerceSync().then(() => {
665 console.log('\nā
E-Commerce sync demonstration completed!');
666}).catch(error => {
667 console.error('ā Demo error:', error);
668});
669
670/*
671šÆ Key Async/Await Patterns Demonstrated:
672
6731. **Sequential Processing**:
674 - Critical operations that must complete in order
675 - Error propagation and fail-fast behavior
676
6772. **Parallel Processing**:
678 - Independent operations using Promise.all/allSettled
679 - Optimized performance through concurrency
680
6813. **Hybrid Workflows**:
682 - Combination of sequential and parallel operations
683 - Complex dependency management
684
6854. **Error Handling Strategies**:
686 - try/catch blocks with granular error recovery
687 - Circuit breaker pattern for resilience
688 - Graceful degradation and fallback handling
689
6905. **Advanced Patterns**:
691 - Retry mechanisms with exponential backoff
692 - Batch processing with concurrency control
693 - Priority-based processing queues
694
6956. **Real-world Integration**:
696 - Realistic API simulation with failures and timeouts
697 - Comprehensive logging and monitoring
698 - Performance tracking and health reporting
699
700This demonstrates how async/await enables building sophisticated,
701production-ready asynchronous systems that handle complex
702business requirements with proper error handling, performance
703optimization, and operational monitoring.
704*/Your progress is saved in this browser, on this device only.