在相同的promise中将用户和头像URL彼此链接

时间:2018-09-25 11:11:52

标签: javascript reactjs firebase promise

需要一些帮助。从firebase,我收集了所有用户,得到了一个包含键值对的对象数组。我要向该对象添加另一个键值对:

avatarUrl: 'someurl'

然后我想将其发送给我的减速器。

我很难将两者结合起来,这是我取得的成就:

const collectionRef = dbf.collection('users');
const collectionArray = [];
collectionRef.get()
    .then((snapshot) => {
        snapshot.forEach((doc) => {
            let withId = {
                docId: doc.id,
                ...doc.data(),
            };
            collectionArray.push(withId);

            storageRef.child(`${doc.id}/avatar.jpg`).getDownloadURL().then((url) => {
                withId = {
                    ...withId,
                    avatarUrl: url,
                };
                collectionArray.push(withId);
            });
        });
        return dispatch({
            type: actionTypes.DONE,
            data: collectionArray,
        });
    })

我在一个诺言中有一个诺言,而事情似乎进展不顺利。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

让我们尝试一下

const collectionRef = dbf.collection('users');
const storageRef = /*...*/

// getAvatarUrl :: String -> Promise String 
const getAvatarUrl = userId =>
  storageRef
    .child(`${userId}/avatar.jpg`)
    .getDownloadURL()

// addDocIdAndAvatar :: Doc -> Promise {docId, ...docData, avatarUrl}
const addDocIdAndAvatar = async doc => ({
  docId: doc.id,
  ...doc.data(),
  avatarUrl: await getAvatarUrl(doc.id)
});

// collectUsersFromSnapshot :: Snapshot -> Dispatch
const collectUsersFromSnapshot = await snapshot =>
  dispatch({
    type: actionTypes.DONE,
    data: await Promise.all(snapshot.map(addDocIdAndAvatar)),
  });

collectionRef.get()
  .then(collectUsersFromSnapshot)

通过对async使用addDocIdAndAvatar函数,我们可以await avatarUrl。同样,在collectUsersFromSnapshot中,我们首先使用addDocIdAndAvatar(一个承诺)映射快照中的用户集合,然后使用Promise.allawait解析整个承诺集合解析度数组,然后传递给dispatch

如果您的设置禁止使用诸如async函数之类的现代JS功能,则可以使用以下等效的流畅版本:

const collectionRef = dbf.collection('users');
const storageRef = /*...*/

// getAvatarUrl :: String -> Promise String 
const getAvatarUrl = userId =>
  storageRef
    .child(`${userId}/avatar.jpg`)
    .getDownloadURL()

// addDocIdAndAvatar :: Doc -> Promise {docId, ...docData, avatarUrl}
const addDocIdAndAvatar = doc => 
  getAvatarUrl(doc.id)
    .then(avatarUrl => ({ docId: doc.id, ...doc.data(), avatarUrl }))

// dispatchUsers :: [User] -> Dispatch
const dispatchUsers = data =>
  dispatch({ type: actionTypes.DONE, data })

// collectUsersFromSnapshot :: Snapshot -> Promise Dispatch
const collectUsersFromSnapshot = snapshot =>
  Promise.all(snapshot.map(addDocIdAndAvatar))
    .then(dispatchUsers)

collectionRef.get()
  .then(collectUsersFromSnapshot)

答案 1 :(得分:0)

@BennyPowers谢谢,由于您的代码,我设法解决了它。快照不是数组,用户数组仅在创建集合数组之后形成。因此必须对其进行一些更改,但最终结果是:这对于asnyc开发有意义吗?

const collectionRef = dbf.collection('users');
const collectionArray = [];
collectionRef.get()
    .then((snapshot) => {
        snapshot.forEach((doc) => {
            let withId = {
                docId: doc.id,
                ...doc.data(),
            };
            collectionArray.push(withId);

            storageRef.child(`${doc.id}/avatar.jpg`).getDownloadURL().then((url) => {
                withId = {
                    ...withId,
                    avatarUrl: url,
                };
                collectionArray.push(withId);
            });
        });

        const getAvatarUrl = userId => storageRef
            .child(`${userId}/avatar.jpg`)
            .getDownloadURL();

        const addDocIdAndAvatar = doc => getAvatarUrl(doc.docId)
            .then(avatarUrl => ({ ...doc, avatarUrl }));

        const dispatchUsers = data => dispatch({ type: actionTypes.DONE, data });
        Promise.all(collectionArray.map(addDocIdAndAvatar))
            .then(dispatchUsers);
    });