JavaScript Promises Tutorial - Section 7: Testing and Debugging
Problem:
function getData() {
fetchUser(1).then(user => {
return user.name; // This return goes to .then(), not getData()
});
// getData() returns undefined!
}
Solution:
function getData() {
return fetchUser(1).then(user => {
return user.name;
});
}
Problem:
fetchUser(1).then(user => {
fetchPosts(user.id).then(posts => {
fetchComments(posts[0].id).then(comments => {
console.log(comments);
});
});
});
Solution:
fetchUser(1)
.then(user => fetchPosts(user.id))
.then(posts => fetchComments(posts[0].id))
.then(comments => console.log(comments));
Problem:
fetchUser(1).then(user => {
console.log(user);
});
// Unhandled rejection if fetchUser fails!
Solution:
fetchUser(1)
.then(user => console.log(user))
.catch(error => console.error('Error:', error));
Problem:
function getUser(id) {
return new Promise((resolve, reject) => {
fetchUser(id)
.then(user => resolve(user))
.catch(error => reject(error));
});
}
Solution:
function getUser(id) {
return fetchUser(id); // Already returns a Promise!
}
Problem (Slow):
const user = await fetchUser(1); // 1s
const posts = await fetchPosts(1); // 1s
const comments = await fetchComments(1); // 1s
// Total: 3 seconds
Solution (Fast):
const [user, posts, comments] = await Promise.all([
fetchUser(1),
fetchPosts(1),
fetchComments(1)
]);
// Total: 1 second
fetchUser(1)
.then(user => {
console.log('User fetched:', user);
return user;
})
.then(user => fetchPosts(user.id))
.then(posts => {
console.log('Posts fetched:', posts);
return posts;
})
.catch(error => {
console.error('Error occurred:', error);
});
async function getData() {
const user = await fetchUser(1);
debugger; // Pause execution here
const posts = await fetchPosts(user.id);
return posts;
}
// Node.js
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise);
console.error('Reason:', reason);
});
// Browser
window.addEventListener('unhandledrejection', event => {
console.error('Unhandled rejection:', event.reason);
event.preventDefault();
});
// ❌ Error: await outside async function
function getData() {
const user = await fetchUser(1);
}
// ✅ Correct
async function getData() {
const user = await fetchUser(1);
}
// ❌ Unhandled rejection
async function getData() {
const user = await fetchUser(1);
return user;
}
// ✅ Proper error handling
async function getData() {
try {
const user = await fetchUser(1);
return user;
} catch (error) {
console.error('Error:', error);
throw error;
}
}
async function measurePerformance() {
console.time('Sequential');
const user1 = await fetchUser(1);
const user2 = await fetchUser(2);
const user3 = await fetchUser(3);
console.timeEnd('Sequential'); // ~3000ms
console.time('Parallel');
const [u1, u2, u3] = await Promise.all([
fetchUser(1),
fetchUser(2),
fetchUser(3)
]);
console.timeEnd('Parallel'); // ~1000ms
}
// Bad: Creates memory leak
const promises = [];
setInterval(() => {
promises.push(fetchData()); // Never cleaned up!
}, 1000);
// Good: Limit array size
const MAX_PROMISES = 100;
const promises = [];
setInterval(() => {
if (promises.length >= MAX_PROMISES) {
promises.shift(); // Remove oldest
}
promises.push(fetchData());
}, 1000);
Ready to put it all together? Check out the course project in Section 8!