【问题标题】:Why does Async firebase fetching is not working? (NODE JS)为什么异步 firebase 提取不起作用? (节点 JS)
【发布时间】:2021-06-08 22:37:42
【问题描述】:

构建 NodeJS REST API。 尝试从 FireBase 集合发送负载数据,然后将其发送给用户(作为 API 响应)。 看起来问题在于它不是等待firebase fetch解决,而是在没有收集数据的情况下发回响应。 (尝试使用 ASYNC-AWAIT 但它不起作用)

exports.getChatMessages = async (req, res, next) => {
  const chatId = req.params.chatId
  const getChatData = () => {
    db
      .collection('chats')
      .doc(chatId)
      .collection('messages')
      .orderBy('timeStamp', 'asc')
      .onSnapshot((snapshot) => {
        snapshot.docs.forEach(msg => {
          console.log(msg.data().messageContent)
          return {
            authorID: msg.data().authorID,
            messageContent: msg.data().messageContent,
            timeStamp: msg.data().timeStamp,
          }
        })
      })
  }
  try {
    const chatData = await getChatData()
    console.log(chatData)
    res.status(200).json({
      message: 'Chat Has Found',
      chatData: chatData
    })
  } catch (err) {
    if (!err.statusCode) {
      err.statusCode(500)
    }
    next(err)
  }
}

如您所见,我使用了 2 个 console.logs 来了解问题所在,终端日志如下所示:

  • [](来自 console.logs(chatData))
  • 所有消息(来自 console.log(msg.data().messageContent))

有什么方法可以在真正获取firebase数据之前阻止代码?

【问题讨论】:

    标签: node.js firebase google-cloud-firestore async-await synchronization


    【解决方案1】:

    如果我理解正确,您想发回 messages 子集合中存在的所有文档的数组。以下应该可以解决问题。

      exports.getChatMessages = async (req, res, next) => {
        const chatId = req.params.chatId;
        const collectionRef = db
          .collection('chats')
          .doc(chatId)
          .collection('messages')
          .orderBy('timeStamp', 'asc');
    
        try {
          const chatsQuerySnapshot = await collectionRef.get();
          const chatData = [];
          chatsQuerySnapshot.forEach((msg) => {
            console.log(msg.data().messageContent);
            chatData.push({
              authorID: msg.data().authorID,
              messageContent: msg.data().messageContent,
              timeStamp: msg.data().timeStamp,
            });
          });
          console.log(chatData);
          res.status(200).json({
            message: 'Chat Has Found',
            chatData: chatData,
          });
        } catch (err) {
          if (!err.statusCode) {
            err.statusCode(500);
          }
          next(err);
        }
      };
    

    异步get() 方法返回一个QuerySnapshot,您可以在其上调用forEach() 以枚举QuerySnapshot 中的所有文档。

    【讨论】:

    • 这也是我解释的完整示例(对结构进行了一些更新)。如果这不起作用,那么其他地方就有问题,因为代码对我来说似乎很好(不管数据操作在哪里完成)。
    • 它有效!用一些承诺更新了代码(我可以使用 await on),将 map 方法更改为 forEach 并且它成功了。 @Renaud 的代码看起来比我的好,向高级开发人员学习总是很好,谢谢你们!
    【解决方案2】:

    你只能await 一个 Promise。目前,getChatData() 没有返回 Promise,所以等待它是没有意义的。您正在尝试等待一个固定值,因此它会立即解析并跳转到下一行。 console.log(chatData) 发生。然后,稍后,您的(snapshot) => 回调发生,但为时已晚。

    const getChatData = () => new Promise(resolve => { // Return a Promise, so it can be awaited
        db.collection('chats')
            .doc(chatId)
            .collection('messages')
            .orderBy('timeStamp', 'asc')
            .onSnapshot(resolve) // Equivalent to .onSnapshot((snapshot) => resolve(snapshot))
    })
    
    
    const snapshot = await getChatData();
    console.log(snapshot)
    
    // Put your transform logic out of the function that calls the DB. A function should only do one thing if possible : call or transform, not both.
    const chatData = snapshot.map(msg => ({
        authorID: msg.data().authorID,
        messageContent: msg.data().messageContent,
        timeStamp: msg.data().timeStamp,
    }));
    
    res.status(200).json({
        message: 'Chat Has Found',
        chatData
    })
    

    【讨论】:

    • 更新了代码,还是一样的问题:(
    • 不可能。我的代码和你的完全不同。你不会得到同样的错误。
    【解决方案3】:

    现在,getChatData 是这个(短版):

    const getChatData = () => {
      db
        .collection('chats')
        .doc(chatId)
        .collection('messages')
        .orderBy('timeStamp', 'asc')
        .onSnapshot((snapshot) => {}) // some things inside
    }
    

    这意味着getChatData 函数调用 一些数据库查询,然后返回void(无)。我敢打赌你会想要返回数据库调用(希望这是一个承诺),以便你的await 为你做一些工作。大致如下:

    const getChatData = async () => 
      db
        .collection('chats')
        // ...
    

    const getChatData = async() => { return db... }一样


    更新:现在我再次查看了文档,我发现您使用了onSnapshot,它用于更新并且可以触发多次。第一个调用实际上是发出请求,但随后会继续侦听这些更新。因为这似乎是一个常规的请求-响应,并且您希望它只发生一次 - 使用 .get() docs 而不是 .onSnapshot()。否则那些听众会留在那里,造成麻烦。 .get() 返回一个 Promise,因此我上面提到的示例修复将完美运行,您无需更改其他代码。

    【讨论】:

    • 这不是 Promise,因为它需要一个回调函数 (.onSnapshot((snapshot) => {)
    • 是的,我看到了。我认为这里不需要,因为它返回响应,所以它应该是对 FireBase 的单次请求。
    • 更改了get,添加了return语句并为getChatDat()使用了异步函数,仍然无法正常工作,看起来getChatData()仍然没有阻止其他代码和console.log( chatData) 在它之前执行.. :(
    • 如果您不更新代码示例,我们将无法帮助您:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-30
    • 2013-05-01
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    相关资源
    最近更新 更多