2

I have an rss.xml.js file that runs this script in a project using the astro framework.

import rss from "@astrojs/rss";
import { fetchFeed } from "../lib/api";

export async function get(context) {
  const posts = await fetchFeed();

  return rss({
    title: "My Online Store",
    description: "Online For Everyone",
    site: context.site,
    items: posts.map((post) => ({
      title: post.title,
      pubDate: Date.now(),
      description: post.description,
      // customData: post.data.customData,
      // Compute RSS link from post `slug`
      // This example assumes all posts are rendered as `/blog/[slug]` routes
      link: post.url,
    })),
  });
}

normally the fetchFeed function has its await functionality and it works fine. However in this particular case I had to make the map method too as an async. That, to me, seems to be the only difference between my previous site, where this worked and the current one, where it's not working.

export const fetchFeed = async function () {
  const allPosts = await import.meta.glob("./../pages/**/*.md");
  // console.log("allPosts", allPosts);
  const posts = Object.values(allPosts).map(async (postData) => {
    const post = await postData();
    // console.log("inside", post.frontmatter);
    return { ...post.frontmatter, url: post.url };
  });

  return posts;
};

When I console.log the posts (in the rss.xml.js) I realise that posts doesn't exist as the fetchFeed function call is not yet resolved. And it resolves after the rss() function has been called.

I assumed the await keyword would delay the return till it was resolved... but that's not what is happening.

Could someone help me and point out what I am doing wrong? I am not very good with Promises and I would appreciate some help.

Regards,

Alim

Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122
Alim Bolar
  • 479
  • 4
  • 17
  • 3
    use `return Promise.all(posts)` - since `posts` is an array of Promises. Now your function caller can wait for that one promise to resolve to an array of results – Jaromanda X Feb 03 '23 at 05:07
  • 1
    `.map()` produces an array. When you pass it an `async` callback function, since all `async` functions return a promise, what you get from `.map()` is an array of promises. You have to use `Promise.all()` to wait for all the promises in the array to resolve and end up with an array of values. – jfriend00 Feb 03 '23 at 05:20
  • 1
    `await` only affects the execution of the nearest `async` function (in this case the one in the `.map()`). It is an easy fix though, because you just have to put an `await` into the outer `async` function too (first you have to convert an array of Promises into a Promise resolving to an array, that's what `Promise.all()` does). – FZs Feb 03 '23 at 05:27
  • Thanks guys ... all your inputs were helpful.. and the issue is resolved! – Alim Bolar Feb 03 '23 at 06:12

2 Answers2

2

Your posts is an array of Promises. You need to await that.

  const posts = await Promise.all(Object.values(allPosts).map(async (postData) => {
    const post = await postData();
    // console.log("inside", post.frontmatter);
    return { ...post.frontmatter, url: post.url };
  }));
Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122
0

Use promise.all

Code will be like this:

export async function get(context) {
  const postsPromises = await fetchFeed();

  const posts = await Promise.all(postsPromises);

  return rss({
    title: "My Online Store",
    description: "Online For Everyone",
    site: context.site,
    items: posts.map((post) => ({
      title: post.title,
      pubDate: Date.now(),
      description: post.description,
      link: post.url,
    })),
  });
}
Mandeep
  • 364
  • 2
  • 16