javascript
examples
examples.js⚡javascript
/**
* ========================================
* 9.3 ASYNC/AWAIT - CODE EXAMPLES
* ========================================
*/
// Helper function for delays
function delay(ms, value) {
return new Promise((resolve) => setTimeout(() => resolve(value), ms));
}
/**
* EXAMPLE 1: Basic Async Function
*/
console.log('--- Example 1: Basic Async Function ---');
async function greet(name) {
return `Hello, ${name}!`;
}
// Async functions always return a promise
greet('Alice').then((message) => console.log(message));
// Equivalent to:
function greetPromise(name) {
return Promise.resolve(`Hello, ${name}!`);
}
/**
* EXAMPLE 2: Using await
*/
console.log('\n--- Example 2: Using await ---');
async function fetchUser(id) {
console.log('Fetching user...');
const user = await delay(100, { id, name: `User ${id}` });
console.log('User fetched:', user);
return user;
}
fetchUser(1);
/**
* EXAMPLE 3: Sequential vs Parallel
*/
console.log('\n--- Example 3: Sequential vs Parallel ---');
async function sequential() {
const start = Date.now();
const a = await delay(50, 'A');
const b = await delay(50, 'B');
const c = await delay(50, 'C');
console.log(`Sequential: ${Date.now() - start}ms`, [a, b, c]);
}
async function parallel() {
const start = Date.now();
const [a, b, c] = await Promise.all([
delay(50, 'A'),
delay(50, 'B'),
delay(50, 'C'),
]);
console.log(`Parallel: ${Date.now() - start}ms`, [a, b, c]);
}
sequential();
parallel();
/**
* EXAMPLE 4: Error Handling with try/catch
*/
console.log('\n--- Example 4: Error Handling ---');
async function riskyOperation(shouldFail) {
await delay(50);
if (shouldFail) {
throw new Error('Operation failed!');
}
return 'Success!';
}
async function handleErrors() {
// Success case
try {
const result = await riskyOperation(false);
console.log('Result:', result);
} catch (error) {
console.error('Error:', error.message);
}
// Failure case
try {
const result = await riskyOperation(true);
console.log('Result:', result);
} catch (error) {
console.error('Error:', error.message);
}
}
handleErrors();
/**
* EXAMPLE 5: Multiple try/catch Blocks
*/
console.log('\n--- Example 5: Multiple try/catch ---');
async function processData() {
let data;
// Step 1: Fetch data
try {
data = await delay(50, { value: 42 });
console.log('Data fetched:', data);
} catch (error) {
console.error('Fetch failed, using default');
data = { value: 0 };
}
// Step 2: Process data
try {
const processed = { ...data, processed: true };
console.log('Processed:', processed);
return processed;
} catch (error) {
console.error('Processing failed:', error);
return null;
}
}
processData();
/**
* EXAMPLE 6: Catching Errors with .catch()
*/
console.log('\n--- Example 6: Inline Error Handling ---');
async function withFallback() {
// Inline error handling with .catch()
const data = await delay(50, 'primary').catch(() => 'fallback');
console.log('Data:', data);
// For conditional error handling
const result = await Promise.reject(new Error('Failed')).catch((e) => {
console.log('Handled:', e.message);
return 'default value';
});
console.log('Result:', result);
}
withFallback();
/**
* EXAMPLE 7: Error Tuple Pattern
*/
console.log('\n--- Example 7: Error Tuple Pattern ---');
async function safeAwait(promise) {
try {
const result = await promise;
return [null, result];
} catch (error) {
return [error, null];
}
}
async function useTuplePattern() {
const [error1, result1] = await safeAwait(delay(50, 'Success!'));
if (error1) {
console.log('Error:', error1.message);
} else {
console.log('Result:', result1);
}
const [error2, result2] = await safeAwait(
Promise.reject(new Error('Failed!'))
);
if (error2) {
console.log('Error:', error2.message);
} else {
console.log('Result:', result2);
}
}
useTuplePattern();
/**
* EXAMPLE 8: Async Arrow Functions
*/
console.log('\n--- Example 8: Arrow Functions ---');
// Arrow function syntax
const fetchData = async (url) => {
const data = await delay(50, { url, content: 'data' });
return data;
};
// In callbacks
const items = [1, 2, 3];
const processItems = async () => {
const results = await Promise.all(
items.map(async (item) => {
return await delay(50, item * 2);
})
);
console.log('Processed items:', results);
};
fetchData('/api').then((data) => console.log('Arrow result:', data));
processItems();
/**
* EXAMPLE 9: Async Methods in Classes
*/
console.log('\n--- Example 9: Class Methods ---');
class DataService {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
async fetch(endpoint) {
console.log(`Fetching ${this.baseUrl}${endpoint}`);
return await delay(50, { endpoint, data: 'result' });
}
async fetchMultiple(endpoints) {
return Promise.all(endpoints.map((e) => this.fetch(e)));
}
}
const service = new DataService('https://api.example.com');
service.fetch('/users').then((data) => console.log('Service result:', data));
/**
* EXAMPLE 10: Loops with async/await
*/
console.log('\n--- Example 10: Loops ---');
// Sequential with for...of
async function processSequentially(items) {
console.log('Processing sequentially:');
for (const item of items) {
const result = await delay(30, `Processed ${item}`);
console.log(result);
}
}
// Parallel with map + Promise.all
async function processInParallel(items) {
console.log('Processing in parallel:');
const results = await Promise.all(
items.map((item) => delay(30, `Processed ${item}`))
);
console.log(results);
}
processSequentially([1, 2, 3]);
processInParallel(['A', 'B', 'C']);
/**
* EXAMPLE 11: forEach Does NOT Work
*/
console.log('\n--- Example 11: forEach Problem ---');
async function forEachProblem() {
const items = [1, 2, 3];
// ❌ This doesn't wait properly
console.log('forEach (broken):');
let completed = 0;
items.forEach(async (item) => {
await delay(50, null);
completed++;
console.log(` Item ${item} done`);
});
console.log(` Completed: ${completed}`); // 0! forEach doesn't wait
// ✅ Use for...of instead
await delay(200); // Wait for forEach to finish for demo
console.log('for...of (correct):');
for (const item of items) {
await delay(50, null);
console.log(` Item ${item} done`);
}
}
forEachProblem();
/**
* EXAMPLE 12: Retry Pattern
*/
console.log('\n--- Example 12: Retry Pattern ---');
async function retry(fn, attempts, delayMs) {
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (error) {
if (i === attempts - 1) throw error;
console.log(`Attempt ${i + 1} failed, retrying...`);
await delay(delayMs);
}
}
}
let attemptCount = 0;
async function flakyFunction() {
attemptCount++;
if (attemptCount < 3) {
throw new Error('Temporary failure');
}
return 'Success!';
}
retry(flakyFunction, 5, 50).then((result) =>
console.log('Retry result:', result)
);
/**
* EXAMPLE 13: Timeout Pattern
*/
console.log('\n--- Example 13: Timeout Pattern ---');
async function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms);
});
return Promise.race([promise, timeout]);
}
async function demonstrateTimeout() {
// Fast enough
try {
const result = await withTimeout(delay(50, 'Quick!'), 200);
console.log('Fast result:', result);
} catch (error) {
console.log('Fast error:', error.message);
}
// Too slow
try {
const result = await withTimeout(delay(300, 'Slow...'), 100);
console.log('Slow result:', result);
} catch (error) {
console.log('Slow error:', error.message);
}
}
demonstrateTimeout();
/**
* EXAMPLE 14: Polling Pattern
*/
console.log('\n--- Example 14: Polling Pattern ---');
let pollCount = 0;
async function checkStatus() {
pollCount++;
return {
ready: pollCount >= 3,
progress: pollCount * 33,
};
}
async function poll(fn, interval, maxAttempts) {
for (let i = 0; i < maxAttempts; i++) {
const result = await fn();
console.log(`Poll ${i + 1}: ${result.progress}%`);
if (result.ready) {
return result;
}
await delay(interval);
}
throw new Error('Polling timeout');
}
poll(checkStatus, 50, 5).then((result) =>
console.log('Poll complete:', result)
);
/**
* EXAMPLE 15: Batched Processing
*/
console.log('\n--- Example 15: Batched Processing ---');
async function processBatch(items, batchSize, processor) {
const results = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
console.log(`Processing batch: ${batch}`);
const batchResults = await Promise.all(batch.map(processor));
results.push(...batchResults);
}
return results;
}
processBatch([1, 2, 3, 4, 5, 6, 7, 8], 3, (n) => delay(50, n * 2)).then(
(results) => console.log('Batch results:', results)
);
/**
* EXAMPLE 16: Async Generator
*/
console.log('\n--- Example 16: Async Generator ---');
async function* asyncGenerator(count) {
for (let i = 1; i <= count; i++) {
const value = await delay(50, i);
yield value;
}
}
async function consumeGenerator() {
console.log('Consuming async generator:');
for await (const value of asyncGenerator(3)) {
console.log(' Generated:', value);
}
}
consumeGenerator();
/**
* EXAMPLE 17: Concurrent Task Limiter
*/
console.log('\n--- Example 17: Concurrency Limiter ---');
class ConcurrencyLimiter {
constructor(limit) {
this.limit = limit;
this.running = 0;
this.queue = [];
}
async run(fn) {
if (this.running >= this.limit) {
await new Promise((resolve) => this.queue.push(resolve));
}
this.running++;
try {
return await fn();
} finally {
this.running--;
if (this.queue.length > 0) {
const next = this.queue.shift();
next();
}
}
}
}
async function demonstrateLimiter() {
const limiter = new ConcurrencyLimiter(2);
const tasks = [1, 2, 3, 4, 5].map((i) => {
return limiter.run(async () => {
console.log(`Task ${i} started`);
await delay(100);
console.log(`Task ${i} done`);
return i;
});
});
const results = await Promise.all(tasks);
console.log('Limiter results:', results);
}
demonstrateLimiter();
/**
* EXAMPLE 18: Async Initialization
*/
console.log('\n--- Example 18: Async Initialization ---');
class AsyncDatabase {
#connection = null;
#ready = null;
constructor(config) {
this.config = config;
this.#ready = this.#initialize();
}
async #initialize() {
console.log('Connecting to database...');
await delay(100);
this.#connection = { connected: true };
console.log('Database connected!');
}
async query(sql) {
await this.#ready; // Wait for initialization
console.log(`Query: ${sql}`);
return [{ id: 1, name: 'Result' }];
}
}
const db = new AsyncDatabase({ host: 'localhost' });
db.query('SELECT * FROM users').then((results) =>
console.log('Query results:', results)
);
/**
* EXAMPLE 19: Async Event Handler
*/
console.log('\n--- Example 19: Async Event Handler ---');
class AsyncEventEmitter {
#handlers = new Map();
on(event, handler) {
if (!this.#handlers.has(event)) {
this.#handlers.set(event, []);
}
this.#handlers.get(event).push(handler);
}
async emit(event, ...args) {
const handlers = this.#handlers.get(event) || [];
const results = [];
for (const handler of handlers) {
const result = await handler(...args);
results.push(result);
}
return results;
}
}
async function demonstrateAsyncEvents() {
const emitter = new AsyncEventEmitter();
emitter.on('data', async (data) => {
await delay(50);
return `Handler 1: ${data}`;
});
emitter.on('data', async (data) => {
await delay(30);
return `Handler 2: ${data}`;
});
const results = await emitter.emit('data', 'test');
console.log('Event results:', results);
}
demonstrateAsyncEvents();
/**
* EXAMPLE 20: Real-World Example - API Client
*/
console.log('\n--- Example 20: Complete API Client ---');
class APIClient {
constructor(baseUrl, options = {}) {
this.baseUrl = baseUrl;
this.timeout = options.timeout || 5000;
this.retries = options.retries || 3;
}
async #request(endpoint, options = {}) {
const { method = 'GET', body, headers = {} } = options;
// Simulate network request
await delay(50);
if (endpoint.includes('error')) {
throw new Error(`Request failed: ${endpoint}`);
}
return {
ok: true,
status: 200,
data: { endpoint, method, message: 'Success' },
};
}
async #requestWithRetry(endpoint, options, attempts = this.retries) {
try {
return await this.#request(endpoint, options);
} catch (error) {
if (attempts <= 1) throw error;
console.log(`Retrying ${endpoint}...`);
await delay(100);
return this.#requestWithRetry(endpoint, options, attempts - 1);
}
}
async get(endpoint) {
return this.#requestWithRetry(endpoint, { method: 'GET' });
}
async post(endpoint, data) {
return this.#requestWithRetry(endpoint, {
method: 'POST',
body: JSON.stringify(data),
});
}
async getMultiple(endpoints) {
const results = await Promise.allSettled(endpoints.map((e) => this.get(e)));
return results.map((result, i) => ({
endpoint: endpoints[i],
success: result.status === 'fulfilled',
data: result.status === 'fulfilled' ? result.value.data : null,
error: result.status === 'rejected' ? result.reason.message : null,
}));
}
}
async function demonstrateAPIClient() {
const api = new APIClient('https://api.example.com');
// Single request
const user = await api.get('/users/1');
console.log('Single request:', user.data);
// Multiple requests
const results = await api.getMultiple(['/users', '/posts', '/error']);
console.log('Multiple requests:', results);
}
demonstrateAPIClient();
console.log('\n========================================');
console.log('End of Async/Await Examples');
console.log('========================================');