# Bab 5: Asynchronous Programming

## Bab 5: Asynchronous Programming

### 5.1 Pengenalan Asynchronous Programming

#### 5.1.1 Konsep Dasar

* Perbedaan Synchronous vs Asynchronous
* Single-threaded nature of JavaScript
* Call Stack dan Event Loop
* Blocking vs Non-blocking operations
* Use cases untuk asynchronous programming

#### 5.1.2 Event Loop Explained

```javascript
console.log('Start');

setTimeout(() => {
    console.log('Timeout 1');
}, 0);

Promise.resolve().then(() => {
    console.log('Promise 1');
});

console.log('End');

// Output:
// Start
// End
// Promise 1
// Timeout 1
```

### 5.2 Callback

#### 5.2.1 Basic Callbacks

```javascript
// Simple callback example
function fetchData(callback) {
    setTimeout(() => {
        const data = { id: 1, name: 'John' };
        callback(data);
    }, 1000);
}

fetchData((result) => {
    console.log(result);
});

// Error handling with callbacks
function fetchDataWithError(success, error) {
    setTimeout(() => {
        const random = Math.random();
        if (random > 0.5) {
            success({ id: 1, name: 'John' });
        } else {
            error(new Error('Failed to fetch data'));
        }
    }, 1000);
}
```

#### 5.2.2 Callback Hell

```javascript
// Example of callback hell
fetchUser(function(user) {
    fetchUserPosts(user.id, function(posts) {
        fetchPostComments(posts[0].id, function(comments) {
            fetchCommentAuthor(comments[0].id, function(author) {
                console.log(author);
            }, function(error) {
                console.error('Error:', error);
            });
        }, function(error) {
            console.error('Error:', error);
        });
    }, function(error) {
        console.error('Error:', error);
    });
}, function(error) {
    console.error('Error:', error);
});

// Solution using named functions
function handleAuthor(author) {
    console.log(author);
}

function handleComments(comments) {
    fetchCommentAuthor(comments[0].id, handleAuthor, handleError);
}

function handlePosts(posts) {
    fetchPostComments(posts[0].id, handleComments, handleError);
}

function handleUser(user) {
    fetchUserPosts(user.id, handlePosts, handleError);
}

function handleError(error) {
    console.error('Error:', error);
}

fetchUser(handleUser, handleError);
```

### 5.3 Promise

#### 5.3.1 Promise Basics

```javascript
// Creating a Promise
const myPromise = new Promise((resolve, reject) => {
    // Async operation
    setTimeout(() => {
        const random = Math.random();
        if (random > 0.5) {
            resolve('Success!');
        } else {
            reject(new Error('Failed!'));
        }
    }, 1000);
});

// Using a Promise
myPromise
    .then(result => console.log(result))
    .catch(error => console.error(error))
    .finally(() => console.log('Completed'));

// Chaining Promises
fetchUser()
    .then(user => fetchUserPosts(user.id))
    .then(posts => fetchPostComments(posts[0].id))
    .then(comments => fetchCommentAuthor(comments[0].id))
    .then(author => console.log(author))
    .catch(error => console.error('Error:', error));
```

#### 5.3.2 Promise Methods

```javascript
// Promise.all
const promises = [
    fetch('/api/users'),
    fetch('/api/posts'),
    fetch('/api/comments')
];

Promise.all(promises)
    .then(([users, posts, comments]) => {
        // All promises resolved
    })
    .catch(error => {
        // Any promise rejected
    });

// Promise.race
Promise.race([
    fetch('/api/fast'),
    fetch('/api/slow')
])
.then(result => {
    // First resolved promise
});

// Promise.allSettled
Promise.allSettled([
    Promise.resolve(1),
    Promise.reject('error'),
    Promise.resolve(3)
])
.then(results => {
    // All promises settled (resolved or rejected)
});

// Promise.any
Promise.any([
    Promise.reject('error'),
    Promise.resolve(1),
    Promise.resolve(2)
])
.then(result => {
    // First fulfilled promise
});
```

### 5.4 Async/Await

#### 5.4.1 Basic Syntax

```javascript
async function fetchUserData() {
    try {
        const user = await fetchUser();
        const posts = await fetchUserPosts(user.id);
        const comments = await fetchPostComments(posts[0].id);
        const author = await fetchCommentAuthor(comments[0].id);
        return author;
    } catch (error) {
        console.error('Error:', error);
    }
}

// Using async/await with Promise methods
async function fetchMultipleData() {
    try {
        const [users, posts, comments] = await Promise.all([
            fetch('/api/users'),
            fetch('/api/posts'),
            fetch('/api/comments')
        ]);
        return { users, posts, comments };
    } catch (error) {
        console.error('Error:', error);
    }
}
```

#### 5.4.2 Error Handling

```javascript
// Try-catch block
async function handleErrors() {
    try {
        const result = await riskyOperation();
        return result;
    } catch (error) {
        console.error('Error:', error);
        throw new Error('Failed to handle operation');
    } finally {
        console.log('Operation completed');
    }
}

// Multiple try-catch blocks
async function complexOperation() {
    try {
        const data = await fetchData();
        try {
            const processed = await processData(data);
            return processed;
        } catch (processingError) {
            console.error('Processing error:', processingError);
            return data; // Return raw data if processing fails
        }
    } catch (fetchError) {
        console.error('Fetch error:', fetchError);
        return null;
    }
}
```

### 5.5 Event Loop dan SetTimeout/SetInterval

#### 5.5.1 SetTimeout

```javascript
// Basic setTimeout
setTimeout(() => {
    console.log('Delayed message');
}, 1000);

// Clearing timeout
const timeoutId = setTimeout(() => {
    console.log('This will not run');
}, 1000);

clearTimeout(timeoutId);

// Nested timeouts
function nestedTimeout() {
    setTimeout(() => {
        console.log('First');
        setTimeout(() => {
            console.log('Second');
        }, 500);
    }, 1000);
}
```

#### 5.5.2 SetInterval

```javascript
// Basic setInterval
const intervalId = setInterval(() => {
    console.log('Repeating message');
}, 1000);

// Clearing interval
setTimeout(() => {
    clearInterval(intervalId);
}, 5000);

// Dynamic interval
let counter = 0;
const dynamicInterval = setInterval(() => {
    console.log(++counter);
    if (counter >= 5) {
        clearInterval(dynamicInterval);
    }
}, 1000);
```

### 5.6 Error Handling

#### 5.6.1 Global Error Handling

```javascript
// Unhandled Promise Rejection
window.addEventListener('unhandledrejection', event => {
    console.error('Unhandled promise rejection:', event.reason);
});

// Global error handler
window.onerror = function(message, source, lineno, colno, error) {
    console.error('Global error:', {
        message,
        source,
        lineno,
        colno,
        error
    });
    return true; // Prevents default error handling
};
```

### 5.7 Praktik dan Latihan

#### 5.7.1 Project: Data Fetching Service

```javascript
class DataService {
    async fetchData(url, options = {}) {
        try {
            const response = await fetch(url, options);
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            return await response.json();
        } catch (error) {
            console.error('Fetch error:', error);
            throw error;
        }
    }

    async fetchMultiple(urls) {
        try {
            const promises = urls.map(url => this.fetchData(url));
            return await Promise.all(promises);
        } catch (error) {
            console.error('Multiple fetch error:', error);
            throw error;
        }
    }
}
```

### 5.8 Best Practices

* Proper error handling
* Avoiding callback hell
* Using async/await when possible
* Managing multiple async operations
* Performance considerations

### 5.9 Ringkasan

* Asynchronous programming fundamentals
* Different approaches to async operations
* Error handling strategies
* Common patterns dan solutions

### 5.10 Latihan Akhir Bab

1. Create a data fetching library
2. Implement a polling system
3. Build an async task queue
4. Create a promise-based cache system
5. Implement retry mechanism for failed requests


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://triyono.gitbook.io/tutorial/java-script/bab-5-asynchronous-programming.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
