firebase storage always return Promise

Viewed 70

I have an application on vue 3. I need to get a link to a document from the repository. At the moment, I always get a promise, which is how it should be. But I should get a link to the document, but it doesn't. Why is this happening?

async FetchData({ state, commit }, to) {
  try {
    commit("setLoading", true);
    const q = query(collection(db, to));

    await onSnapshot(q, (querySnapshot) => {
      const data = [];

      querySnapshot.forEach((doc) => {
        let films = async (to) => {
          const starsRef = ref(storage, `images/${doc.id}/poster.png`);

          return await getDownloadURL(starsRef);
        };

        // const poster=`gs://cell-11ef4.appspot.com/images/${doc.id}/poster.png`

        let item = {
          id: doc.id,
          name: doc.data().name,
          slug: doc.data().slug,
          country: doc.data().country,
          duration: doc.data().duration,
          year: doc.data().year,
          video: doc.data().video,
          genres: doc.data().genres,
          actors: doc.data().actors,
          poster: to === "films" ? films() : null,
          // BipPoster: url,
        };

        data.push(item);

        // Get the download URL
      });

      commit("setData", { data, to });
    });
  } catch (err) {
    console.log(err);
  } finally {
    commit("setLoading", false);
  }
}
let url = async () => {
  let url;
  const starsRef = ref(storage, `images/${doc.id}/poster.png`);

  await getDownloadURL(starsRef).then((p) => {
    url = p;
  });

  return url;
};

What i get

enter image description here

enter image description here enter image description here

3 Answers

You should use Promise.all() as follows:

const promises = [];
querySnapshot.forEach((doc) => {
     const starsRef = ref(storage, `images/${doc.id}/poster.png`);

     promises.push(getDownloadURL(starsRef));
});

const urlsArray = await Promise.all(promises);

Map the documents collection to an array of promises that resolve with the full item data, including download URL and await them all with Promise.all().

You're also registering a real-time updates listener which seems counter to what you seem to want FetchData to do. I would suggest you want to use getDocs() instead of onSnapshot()

async FetchData({ state, commit }, to) {
  try {
    commit("setLoading", true);

    // `onSnapshot` registers a real-time updates listener,
    // use `getDocs` to retrieve documents
    const { docs } = await getDocs(query(collection(db, to)));

    // Map over the `docs` array and return fully hydrated objects
    const data = await Promise.all(
      docs.map(async (doc) => ({
        ...doc.data(),
        id: doc.id,
        poster:
          to === "films"
            ? await getDownloadURL(ref(storage, `images/${doc.id}/poster.png`))
            : null,
      }))
    );

    commit("setData", { data, to });
  } catch (err) {
    console.error(err);
  } finally {
    commit("setLoading", false);
  }
},

If you did want to register a real-time updates listener, do so in an effect hook where you can also remove the listener in a cleanup

useEffect(() => {
  // Return the unsub function as cleanup
  return onSnapshot(query(collection(db, to)), async ({ docs }) => {
    try {
      const data = await Promise.all(
        docs.map(async (doc) => ({
          ...doc.data(),
          id: doc.id,
          poster:
            to === "films"
              ? await getDownloadURL(
                  ref(storage, `images/${doc.id}/poster.png`)
                )
              : null,
        }))
      );

      commit("setData", { data, to });
    } catch (err) {
      console.error(err);
    }
  });
}, [to]);

async FetchData({ state, commit }, to) {
  try {
    const q = query(collection(db, to));

    await onSnapshot(q, (querySnapshot) => {
      const allPromises = querySnapshot.docs.map(async (doc) => {
        let item = {
          id: doc.id,
          name: doc.data().name,
          slug: doc.data().slug,
          country: doc.data().country,
          duration: doc.data().duration,
          year: doc.data().year,
          video: doc.data().video,
          genres: doc.data().genres,
          actors: doc.data().actors
        };
        if (to === "films") {
          const starsRef = ref(storage, `images/${doc.id}/poster.png`);
          item.poster = await getDownloadURL(starsRef);
        }
        return item;
      });
      Promise.all(allPromises)
        .then((data) => commit("setData", { data, to }))
        .catch(console.error);
    });
  } catch (err) {
    console.error(err);
  }
}

Related