TypeScript数组的Promise在一种情况下可以正确解决,而在另一种情况下则不能

时间:2019-03-18 00:06:24

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

我有一个函数,该函数映射一个数组的每个元素(在这种情况下为电子邮件地址),产生一个应答数组,应解析为Firebase自动生成的文档ID(即hAvJ3qPq821tq1q2rrEv, 0tjeKB1aW8jsOAse5fcP)。

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: ,

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

3 个答案:

答案 0 :(得分:1)

  

当文档中还没有所有参与者的电子邮件时,该功能将按预期运行,console.log()输出最终文档ID:hAvJ3qPq821tq1q2rrEv,0tjeKB1aW8jsOAse5fcP

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

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;

答案 1 :(得分:1)

如果使用Promise.all,即使1个承诺都失败了,您也不会得到任何结果。请看以下示例:

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

答案 2 :(得分:1)

用@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);
    }
};