Firestore异步等待foreach与for

时间:2020-06-30 11:53:56

标签: reactjs typescript react-native google-cloud-firestore async-await

我正在使用Firestore一段时间,我想实现一个调用以从子集合中获取数据。

我必须创建一个异步调用,并且foreach()方法未等待调用并继续执行,但是它与for()方法一起使用。有人可以向我解释为什么for()等待而foreach()没有等待吗?

Foreach()-不起作用

export const FirebaseSearchUsers = async (search: string) => {
  const end = search.replace(/.$/, c => String.fromCharCode(c.charCodeAt(0) + 1));
  let users: UserDocument[] = [];

  await firestore()
    .collection(FirebaseConstraints.UserCollection)
    .where('username', '>=', search)
    .where('username', '<', end)
    .limit(10)
    .get()
    .then(async x => {
      x.forEach(async y => {
        let userDocument: UserDocument = y.data() as UserDocument;
        userDocument.houseInvites = [];

        await y.ref
          .collection(FirebaseConstraints.HouseInvitesCollection)
          .get()
          .then(x => x.forEach(x => userDocument.houseInvites.push(x.data() as HouseInviteDocument)));
        users.push(userDocument);
      });
    });
  return users;
};

For()-作品

export const FirebaseSearchUsers = async (search: string) => {
  const end = search.replace(/.$/, c => String.fromCharCode(c.charCodeAt(0) + 1));
  let users: UserDocument[] = [];

    await firestore()
    .collection(FirebaseConstraints.UserCollection)
    .where('username', '>=', search)
    .where('username', '<', end)
    .limit(10)
    .get()
    .then(async x => {
      for (let y of x.docs) {
        let userDocument: UserDocument = y.data() as UserDocument;
        userDocument.houseInvites = [];
        await y.ref
          .collection(FirebaseConstraints.HouseInvitesCollection)
          .get()
          .then(x => x.forEach(x => userDocument.houseInvites.push(x.data() as HouseInviteDocument)));
        users.push(userDocument);
      }
    });
  return users;
};

1 个答案:

答案 0 :(得分:2)

Foreach期望同步回调;)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Polyfill

(第二条黄色备忘录)

您的版本不错,但受阻。 (您可以并行处理秒数请求以更快地获得结果)

编辑

要并行化,也许这应该有用;)

export const FirebaseSearchUsers = async (search: string) => {
  const end = search.replace(/.$/, c => String.fromCharCode(c.charCodeAt(0) + 1));

  // wrap this in try catch to handle errors ;)

    const usersQuerySnapshot = await firestore()
    .collection(FirebaseConstraints.UserCollection)
    .where('username', '>=', search)
    .where('username', '<', end)
    .limit(10)
    .get();

    const futureUsers = usersQuerySnapshot.docs.map(async userSnapshot => {
      const userDocument: UserDocument = userSnapshot.data() as UserDocument;

      const houseInvitesSnapshots = await userSnapshot.ref
      .collection(FirebaseConstraints.HouseInvitesCollection)
      .get();

      const houseInvites = houseInvitesSnapshots.docs.map(snapshot => snapshot.data() as HouseInviteDocument);

      // or you can use the builtin method forEach of houseInvitesSnapshots and declare a "let" houseInvites array
      // let houseInvites = [];
      // houseInvitesSnapshots.forEach(snapshot => houseInvites.push(snapshot.data() as HouseInviteDocument));
      // these 2 forms should works same (I did not test ;)

      // Then, return a copy of your user document and fill its houseInvites property
      return { ...userDocument, houseInvites};
    })

    const users = await Promise.all(futureUsers);

    return users;
};