使用 async/await 时,Firebase Cloud Firestore 查询返回 Promise <pending> 而不是已完成

Posted

技术标签:

【中文标题】使用 async/await 时,Firebase Cloud Firestore 查询返回 Promise <pending> 而不是已完成【英文标题】:Firebase Cloud Firestore query returning Promise <pending> instead of fulfilled when using async/await使用 async/await 时,Firebase Cloud Firestore 查询返回 Promise <pending> 而不是已完成 【发布时间】:2020-11-29 01:16:51 【问题描述】:

This question 类似,但没有帮助。

目标是将 async/await 与 Firebase Cloud Firestore 查询一起使用,而不是 the Firebase documentation 中的 then/catch Promise 代码。

但是,下面的函数在否定情况下成功拒绝,但返回 Promise &lt;pending&gt; 而不是 Cloud Firestore 文档。

async getUser(emailAddress) 
    // Return null if @emailAddress blank.
    if (!emailAddress) 
        return null;
    

    // Assume @db points to a Cloud Firestore database. Query only returns one doc.
    let query = db.collection('users').where('emailAddress', '==', emailAddress);
    try 
        let querySnapshot = await query.get();
        querySnapshot.forEach(function(doc) 
           return doc.data();               
        );
     catch(e) 
        console.log('Error getting user: ', e);
    

【问题讨论】:

【参考方案1】:

如果 emailAddress 不为 null 或未定义,则您的函数不返回任何内容,因为forEach() 返回 void。

由于querySnapshot 中只有一个文档,您可以执行以下操作:

async getUser(emailAddress) 
    // Return null if @emailAddress blank.
    if (!emailAddress) 
        return null;
    

    // Assume @db points to a Cloud Firestore database. Query only returns one doc.
    const query = db.collection('users').where('emailAddress', '==', emailAddress);
    try 
        const querySnapshot = await query.get();
        return querySnapshot.docs[0].data();               
     catch(e) 
        console.log('Error getting user: ', e);
    

请注意,您的 getUser() 函数本身是异步的,因此您需要在它返回的 Promise 实现时使用 then()(或 async/await)来获取 doc 值。

const emailAddress = "john@gmail.com";
getUser(emailAddress).
then(userData =>  ... )

【讨论】:

【参考方案2】:

您正试图从forEach 返回,但forEach 不返回任何内容,而是循环遍历元素并允许您修改它们。

您可以像这样修改您的代码,例如:

async getUser(emailAddress) 
    // Return null if @emailAddress blank.
    if (!emailAddress) 
        return null;
    

    // Assume @db points to a Cloud Firestore database. Query only returns one doc.
    let query = db.collection('users').where('emailAddress', '==', emailAddress);
    try 
        const results = [];
        let querySnapshot = await query.get();
        querySnapshot.forEach(function(doc) 
           results.push(doc.data());               
        );
        return results;
     catch(e) 
        console.log('Error getting user: ', e);
    

更多关于forEach的信息:

forEach() 对每个数组元素执行一次回调函数; 不像 map() 或 reduce() 它总是返回值 undefined 并且是 不可链接。典型的用例是在 链的末端。

【讨论】:

【参考方案3】:

async 函数,例如你的函数,总是返回一个承诺。这是无法避免的。所有的异步行为仍然存在于函数中,调用者仍然需要awaitthen 来获取promise 中的值。你不能使用 async/await 来移除一个 Promise 并立即返回。

最重要的是,您的函数实际上并不返回任何文档。 forEach 中的返回实际上只是从您传递给 forEach 的内联 lambda 函数返回。该返回不会扩展到封闭的 getUser 函数。

如果您想有效地使用 async/await,该函数仍然必须从其顶层返回一个值。调用者仍然需要使用 await 或 then 来从返回的 promise 中获取值。

【讨论】:

以上是关于使用 async/await 时,Firebase Cloud Firestore 查询返回 Promise <pending> 而不是已完成的主要内容,如果未能解决你的问题,请参考以下文章

使用 async / await 在 firebase 中运行查询

将 async/await (Swift 5.5) 与 firebase 实时数据库一起使用

处理 Async Await 以使用 Firebase 和 react native

使用 useEffect() Hook 和 Async/Await 从 Firebase/Firestore 获取数据

async/await 与 firebase .on() 数据库监听器

Firebase:Flutter:避免事务崩溃 CloudFirestorePlugin.java:613 : .then() vs async/await