【问题标题】:firestore async await foreach vs forfirestore 异步等待 foreach 与 for
【发布时间】:2020-10-20 17:19:49
【问题描述】:

我现在使用 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;
};

【问题讨论】:

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


    【解决方案1】:

    Foreach 期望同步回调 ;)

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

    (第二份黄色备忘录)

    您的 for 版本很好,但它会阻塞。 (您可以并行化您的秒请求以更快地获得结果)

    编辑

    为了并行化,也许这应该可行;)

    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;
    };
    

    【讨论】:

    • 这说明了很多(:你对并行化部分有什么想法?例如 Promise.all?
    • 是的,parallelize 会在多个异步调用中中断您的异步调用并等待所有调用完成。而不是在 for 循环中一个一个地等待,所有异步调用都会触发,并且使用 Promise.all(allMyAsyncCallsArray) 你会得到一个包含结果的数组。很难在此评论中展示 ^^
    • 我编辑我的答案。我无法测试它是否有效,但我希望你明白这一点。编码愉快!
    • 试过代码,完美!非常感谢你解释和帮助我。你是 MVP,干杯。
    猜你喜欢
    • 2018-05-04
    • 2019-04-20
    • 2020-10-17
    • 2019-06-29
    • 2021-08-13
    • 2014-11-23
    • 2017-01-11
    • 2021-09-19
    相关资源
    最近更新 更多