Advanced JavaScript

Master advanced JavaScript concepts including design patterns, performance optimization, and modern development practices.

advanced JavaScript 7 hours

Chapter 6: Asynchronous Programming Advanced

Chapter 6 of 15

Chapter 6: Asynchronous Programming Advanced

6.1 Promises Advanced

Promises provide a cleaner way to handle asynchronous operations. Understanding advanced Promise patterns is essential for modern JavaScript development.

Promise.all() - Wait for All:

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve) => {
    setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3])
    .then(values => {
        console.log(values); // [3, 42, "foo"]
    })
    .catch(error => {
        console.error(error); // If any promise rejects
    });

Promise.allSettled() - Wait for All (Even Rejected):

const promises = [
    Promise.resolve('success'),
    Promise.reject('error'),
    Promise.resolve('another success')
];

Promise.allSettled(promises)
    .then(results => {
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                console.log(`Promise ${index}:`, result.value);
            } else {
                console.log(`Promise ${index}:`, result.reason);
            }
        });
    });

Promise.race() - First to Resolve/Reject:

const promise1 = new Promise((resolve) => 
    setTimeout(resolve, 500, 'First'));
const promise2 = new Promise((resolve) => 
    setTimeout(resolve, 100, 'Second'));

Promise.race([promise1, promise2])
    .then(value => {
        console.log(value); // "Second" - fastest
    });

Promise Chaining:

fetch('/api/user')
    .then(response => response.json())
    .then(user => {
        return fetch(`/api/posts/${user.id}`);
    })
    .then(response => response.json())
    .then(posts => {
        console.log(posts);
    })
    .catch(error => {
        console.error('Error:', error);
    });

6.2 Async/Await Patterns

Async/await provides a more readable way to write asynchronous code, making it look like synchronous code.

// Basic async/await
async function fetchUserData(userId) {
    try {
        const response = await fetch(`/api/users/${userId}`);
        const user = await response.json();
        return user;
    } catch (error) {
        console.error('Error fetching user:', error);
        throw error;
    }
}

Parallel Execution:

async function fetchMultipleData() {
    try {
        // Execute promises in parallel
        const [users, posts, comments] = await Promise.all([
            fetch('/api/users').then(r => r.json()),
            fetch('/api/posts').then(r => r.json()),
            fetch('/api/comments').then(r => r.json())
        ]);
        
        return { users, posts, comments };
    } catch (error) {
        console.error('Error:', error);
    }
}

Sequential Execution:

async function processSequentially() {
    const step1 = await doStep1();
    const step2 = await doStep2(step1);
    const step3 = await doStep3(step2);
    return step3;
}

Error Handling Patterns:

// Pattern 1: Try-catch
async function withTryCatch() {
    try {
        const data = await fetchData();
        return data;
    } catch (error) {
        // Handle error
        return null;
    }
}

// Pattern 2: Catch on promise
async function withCatch() {
    const data = await fetchData().catch(error => {
        console.error(error);
        return null;
    });
    return data;
}

// Pattern 3: Wrapper function
function asyncHandler(fn) {
    return function(req, res, next) {
        Promise.resolve(fn(req, res, next))
            .catch(next);
    };
}

6.3 Advanced Promise Patterns

Retry Pattern:

async function retryOperation(fn, retries = 3, delay = 1000) {
    for (let i = 0; i < retries; i++) {
        try {
            return await fn();
        } catch (error) {
            if (i === retries - 1) throw error;
            await new Promise(resolve => setTimeout(resolve, delay));
        }
    }
}

Timeout Pattern:

function withTimeout(promise, timeoutMs) {
    const timeout = new Promise((_, reject) => {
        setTimeout(() => reject(new Error('Timeout')), timeoutMs);
    });
    
    return Promise.race([promise, timeout]);

}

// Usage
const data = await withTimeout(
    fetch('/api/data').then(r => r.json()),
    5000 // 5 second timeout
);