简体   繁体   English

Promise 在异步 function 内的循环内

[英]Promise inside a loop inside an async function

I am working on a project using react and firebase and redux and I have some items that did created by a user.我正在使用 react 和 firebase 和 redux 开展一个项目,我有一些由用户创建的项目。 I'm storing the id of the user in the item object so i can populate the user later when i get the item to display.我将用户的 id 存储在项目 object 中,以便稍后在我获得要显示的项目时填充用户。

Now I'm trying to get the items and modify them by replacing the user id with the actual info about the user but I have a promises problem.现在我正在尝试获取项目并通过将用户 ID 替换为有关用户的实际信息来修改它们,但我有一个承诺问题。 In my code I just get an empty array which mean the modification didn't get resolved before I return the final result.在我的代码中,我只得到一个空数组,这意味着在我返回最终结果之前修改没有得到解决。

export const getItems = () => {
  return (dispatch, getState, { getFirebase }) => {
    const firestore = getFirebase().firestore();
    const items = [];
    const dbRef = firestore.collection('items').orderBy('createdAt', 'desc').limit(2);

    return dbRef
      .get()
      .then((res) => {
        const firstVisible = res.docs[0];
        const lastVisible = res.docs[res.docs.length - 1];

        async function getData(res) {

/////////////////////////////////////////////// how to finish this code befor jumping to the return line
          await res.forEach((doc) => {
            firestore
              .collection('users')
              .doc(doc.data().owner)
              .get()
              .then((res) => {
                items.push({ ...doc.data(), owner: res.data() });
              });
          });
////////////////////////////////////////////////

          return { docs: items, lastVisible, firstVisible };
        }

        return getData(res);
      })
      .catch((err) => {
        console.log(err);
      });
  };
};

I don't get exactly what you are trying to do, but I would suggest putting some order to make your code easy to read and work with.我不完全了解您要做什么,但我建议您安排一些订单以使您的代码易于阅读和使用。

You can use for of to manage async looping.您可以使用for of来管理异步循环。 I suggest something like this, disclaimer, I did it at the eye, problably there are some errors, but you can get the idea.我建议这样的事情,免责声明,我是在眼睛上做的,可能有一些错误,但你可以明白。

const getAllDocs = function (data) {
    let temp = [];
    data.forEach(function (doc) {
        temp.push(doc.data());
    });
    return { data: temp };
};

const getDoc = snap => (snap.exists ? { data: snap.data() } : {});

export const getItems = () => {
    return async (dispatch, getState, { getFirebase }) => {
        const firestore = getFirebase().firestore();
        const dbRef = firestore.collection('items').orderBy('createdAt', 'desc').limit(2);
        const usersRef = firestore.collection('users');
        let temps = [];

        const { data: items } = await dbRef.get().then(getAllDocs);
        const firstVisible = items[0];
        const lastVisible = items[items.length - 1];

        for (const item of items) {
            const { data: user } = await usersRef.doc(item.owner).get().then(getDoc);
            const owner = {
                /* whatever this means*/
            };
            temps.push({ ...user, owner });
        }

        return { docs: temps, lastVisible, firstVisible };    
    };
};

The problem is that an array of Promises is not itself a Promise -- so await ing it will be a no-op.问题是 Promise 数组本身并不是 Promise - 所以await它将是一个空操作。

You can solve this using Promise.all if you want to load them all asynchronously.如果你想异步加载它们,你可以使用Promise.all来解决这个问题。

const items = await Promise.all(res.map(async (doc) => {
  const res = await firestore.collection('users').doc(doc.data().owner).get();
  return { ...doc.data(), owner: res.data() };
});

Otherwise you can await in a for loop as suggested in other answers.否则,您可以按照其他答案中的建议在 for 循环中await

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM