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
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
// 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
// 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
// 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
// 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
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
// 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
// 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
// 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
// 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
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
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
Create a data fetching library
Implement a polling system
Build an async task queue
Create a promise-based cache system
Implement retry mechanism for failed requests