【问题标题】:Typescript array of promises resolving properly in one case but not in another承诺的打字稿数组在一种情况下正确解决,但在另一种情况下则不正确
【发布时间】:2019-08-08 08:07:52
【问题描述】:

我有一个函数可以映射数组的每个元素(在本例中为电子邮件地址),生成一组应解析为 Firebase 自动生成的文档 ID(即hAvJ3qPq821tq1q2rrEv, 0tjeKB1aW8jsOAse5fcP)的 Promise。

async function addMultipleParticipants(participant_emails: Array<string>) {
    console.log("Parallelizing participant processing");
    const promises = participant_emails.map(addParticipant);
    const document_ids = await Promise.all(promises);
    console.log("Final document ids: " + document_ids);
    return document_ids;
};

这是返回文档 ID 的函数,具体取决于它是否可以找到与电子邮件地址关联的现有文档或需要创建新文档。

async function addParticipant(email_address: string) {
    try {
        console.log("Querying for person");
        const query = await db.collection('people')
            .where('emails', 'array-contains', email_address)
            .limit(1);
        const querySnapshot = await query.get();
        if (!querySnapshot.empty) {
            console.log("Document exists for email " + email_address);
            // TODO: There is only one, so we shouldn't have to iterate
            querySnapshot.forEach(function(docRef: any) {
                console.log("New document id: " + docRef.id);
                const document_id = docRef.id;
                return document_id;
            });
        } else {
            console.log("Creating person with " + email_address);
            const fields = {emails: [email_address]};
            try {
                const docRef = await db.collection('people').add(fields);
                console.log("New document id: " + docRef.id);
                const document_id = docRef.id;
                return document_id;
            } catch (err) {
                console.log("Error adding document:", err);
            }
        }
    } catch (err) {
        console.log("Error getting document:", err);
    }
};

当文档中尚不存在所有参与者电子邮件时,函数按预期工作,console.log() 输出 Final document ids: hAvJ3qPq821tq1q2rrEv, 0tjeKB1aW8jsOAse5fcP

但是,当至少一个电子邮件地址与现有文档相关联时,来自addParticipant() 的承诺不会解析为任何内容,并且console.log() 会输出Final document ids: ,

在这种情况下,我需要做些什么来确保 Promise 数组在 addMultipleParticipants() 中正确解析?

【问题讨论】:

    标签: javascript typescript firebase promise google-cloud-firestore


    【解决方案1】:

    当文档中尚不存在所有参与者电子邮件时,函数按预期工作,console.log() 输出最终文档 ids:hAvJ3qPq821tq1q2rrEv, 0tjeKB1aW8jsOAse5fcP

    这是因为它解析为以下返回语句:

    return document_id;
    

    但是,当至少一个电子邮件地址与现有文档相关联时,来自 addParticipant() 的承诺不会解析为任何内容

    因为它返回任何东西。您的最后一条语句是:

            // TODO: There is only one, so we shouldn't have to iterate
            querySnapshot.forEach(function(docRef: any) {
                console.log("New document id: " + docRef.id);
                const document_id = docRef.id;
                return document_id;
            });
    

    不是任何id的返回。它只是一个forEach。修复示例如下:

            // Return the id
            return querySnapshot[0].document_id;
    

    【讨论】:

    • 谢谢,看起来很有希望! (没有双关语。)但是,当我尝试return querySnapshot[0].document_id 时,它导致了一个错误(TypeError: Cannot read property 'document_id' of undefined)。我应该指出document_id 不是文档中的字段——我真正想要的是people 集合中特定文档的ID。
    • 我也试过return querySnapshot.getDocuments()[0].getId();,基于​​Google's documentation,但它抛出了这个错误:TypeError: querySnapshot.getDocuments is not a function
    【解决方案2】:

    使用Promise.all,即使有 1 个 promise 失败,您也不会得到其中任何一个的结果。举个例子:

    const get = async () => {
        return Promise.all([
            new Promise((res, rej) => {
                setTimeout(() => {
                    res('data!')
                }, 1000)
            }),
            new Promise((res, rej) => {
                setTimeout(() => {
                    rej('error!')
                }, 2000)
            })
        ]);
    }
    
    const start = async () => {
        const response = await get()
        console.log(response)
    }
    
    start()
    

    您只会收到Uncaught (in promise) error! 错误。

    现在,如果您想解决这个问题以至少获得一些回报,您可以像这样对每个承诺使用catch

    const get = async () => {
        return Promise.all([
            new Promise((res, rej) => {
                setTimeout(() => {
                    res('data!')
                }, 1000)
            }).catch(err => {
                return null
            }),
            new Promise((res, rej) => {
                setTimeout(() => {
                    rej('error!')
                }, 2000)
            }).catch(err => {
                return null
            })
        ]);
    }
    
    const start = async () => {
        const response = await get()
        console.log(response)
    }
    
    start()
    

    这将为您提供["data!", null],您可以根据需要处理null

    【讨论】:

      【解决方案3】:

      通过@basarat 的一些提示想通了。第一个结果应该有一个明确的返回,而不是一个 for 循环:return querySnapshot.docs[0].id;。修改后的完整功能如下:

      async function addParticipant(email_address: string) {
          try {
              console.log("Querying for person");
              const query = await db.collection('people')
                  .where('emails', 'array-contains', email_address)
                  .limit(1);
              const querySnapshot = await query.get();
              if (!querySnapshot.empty) {
                  console.log("Document exists for email " + email_address);
                  return querySnapshot.docs[0].id;
              } else {
                  console.log("Creating person with " + email_address);
                  const fields = {emails: [email_address]};
                  try {
                      const docRef = await db.collection('people').add(fields);
                      console.log("New document id: " + docRef.id);
                      const document_id = docRef.id;
                      return document_id;
                  } catch (err) {
                      console.log("Error adding document:", err);
                  }
              }
          } catch (err) {
              console.log("Error getting document:", err);
          }
      };
      

      【讨论】:

        猜你喜欢
        • 2017-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-25
        • 1970-01-01
        • 2013-07-05
        • 2018-09-15
        相关资源
        最近更新 更多