From https://www.learnwithjason.dev/blog/keep-async-await-from-blocking-execution, I saw the 1st block of code log wrong values for post, while 2nd block of code logs correct values.
Utility Functions for both wrong and right versions
function getBlogPosts() {
const posts = [
{ id: 1, title: 'Post One', body: 'A blog post!' },
{ id: 2, title: 'Post Two', body: 'Another blog post!' },
{ id: 3, title: 'Post Three', body: 'A third blog post!' },
];
return new Promise((resolve) => {
setTimeout(() => resolve(posts), 200);
});
}
function getBlogComments(postId) {
const comments = [
{ postId: 1, comment: 'Great post!' },
{ postId: 2, comment: 'I like it.' },
{ postId: 1, comment: 'You make interesting points.' },
{ postId: 3, comment: 'Needs more corgis.' },
{ postId: 2, comment: 'Nice work!' },
];
// get comments for the given post
const postComments = comments.filter((comment) => comment.postId === postId);
return new Promise((resolve) => {
setTimeout(() => resolve(postComments), 300);
});
}
Wrong version The ...post always contains details from the 3rd post, even though comments are from post 1 and 2
function loadContent() {
getBlogPosts().then((posts) => {
for (post of posts) {
getBlogComments(post.id).then((comments) => {
console.log({ ...post, comments });
});
}
});
}
loadContent();
Correct version Comments from post 1 and 2 are correctly stored with respectively posts
async function loadContent() {
const posts = await getBlogPosts();
// instead of awaiting this call, create an array of Promises
const promises = posts.map((post) => {
return getBlogComments(post.id).then((comments) => {
return { ...post, comments };
});
});
// use await on Promise.all so the Promises execute in parallel
const postsWithComments = await Promise.all(promises);
console.log(postsWithComments);
}
loadContent();
- Why does the wrong version not log the correct post from the looping variable? Ideally the explanation can focus on how lexical environments work with Promises, assuming that's relevant to this bug
- Is there a way to fix the wrong version without map? Maybe for some reason I cannot have things run in parallel, which the map + Promise.all pattern does.