【问题标题】:Firestore return after promise承诺后Firestore返回
【发布时间】:2018-01-01 23:22:37
【问题描述】:

我正在使用 Firestore、Cloud Functions 和 Dialogflow 来创建 Google Home 应用。我的云函数应该根据集合中的值返回一个计算,但我只能返回一个 Promise。

// query firestore based on user
var transactions = db.collection('accounts')
               .doc(request.body.result.parameters.accountowner)
               .collection('transactions');
var accountbalance = await transactions.get()
    .then(snapshot => {
        var workingbalance = 0
        snapshot.forEach(doc => {
            workingbalance = workingbalance + doc.data().amount;
        });
        return workingbalance
    })
    .catch(err => {
        console.log('Error getting transactions', err);
    });

console.log(accountbalance)
balanceresponse = {
    "speech": request.body.result.parameters.accountowner + " has a balance of $" + accountbalance,
    "displayText": request.body.result.parameters.accountowner + " has an account balance of $" + accountbalance,
    "data": {},
    "contextOut": [],
    "source": "system"
}

response.send(balanceresponse);    

如何在调用 response.send 之前等待 promise 返回实际值?我也尝试将 response.send 放在 then 中,但函数完成并在操作完成之前发送标头。

【问题讨论】:

标签: javascript node.js firebase google-cloud-firestore google-cloud-functions


【解决方案1】:

如果您使用 Promise,则需要将值作为 Promise.then 链的一部分返回。这通常是通过将一堆.then() 调用/块链接在一起来完成的。请记住,then() 部分只会在 Promise 解析时被调用。

在您的情况下,您似乎可以在同一代码块内计算workingbalance 后生成balanceresponse 并调用response.send()。对response.send() 的调用不需要在函数的末尾。因此,您可能会使该块看起来像:

.then(snapshot => {
    var workingbalance = 0
    snapshot.forEach(doc => {
        workingbalance = workingbalance + doc.data().amount;
    });

    balanceresponse = {
      "speech": request.body.result.parameters.accountowner + " has a balance of $" + workingbalance,
      "displayText": request.body.result.parameters.accountowner + " has an account balance of $" + workingbalance,
      "data": {},
      "contextOut": [],
      "source": "system"
    }

    response.send(balanceresponse); 
})

如果出于某种原因,您想分开计算并在不同的块中计算 balanceresponse,您可以这样做。我不一定推荐这个,但它有一些优点(例如,您可以在每个部分之后放置多个 catch 块,我在这里展示过):

// query firestore based on user
var transactions = db.collection('accounts')
               .doc(request.body.result.parameters.accountowner)
               .collection('transactions');
await transactions.get()

    .then(snapshot => {
        var workingbalance = 0
        snapshot.forEach(doc => {
            workingbalance = workingbalance + doc.data().amount;
        });
        return workingbalance
    })

    .catch(err => {
        console.log('Error getting transactions', err);
    });

    .then( accountbalance => {
        balanceresponse = {
            "speech": request.body.result.parameters.accountowner + " has a balance of $" + accountbalance,
            "displayText": request.body.result.parameters.accountowner + " has an account balance of $" + accountbalance,
            "data": {},
            "contextOut": [],
            "source": "system"
        }
        response.send(balanceresponse);    
    })

    .catch(err => {
        console.log('Error sending response', err);
    });

【讨论】:

  • 我以前尝试过这个(现在又一次)。问题是response.send需要同步调用。当我将它留在.then 中时,它确实会尝试发送响应,但该函数已经退出,因此请求者(在本例中为 Dialogflow)永远不会得到响应。
  • 那你在其他地方有问题。 {: response.send() 不需要同步调用 - 我也为 Actions on Google 执行了这个确切的场景(使用实时数据库而不是 firestore)。假设“响应”是传递给云函数的参数之一。这个函数是怎么调用的?您是否可以发布您所看到的最小、完整的代码示例?
  • 我添加了一个包含导出功能的要点的链接
  • 在您发布的要点中,第 13 行从调用 response.send() 之前的函数返回。请注意,我已从上面的第一个示例块中删除了它。 (我还修复了该示例中的变量名称用法。)
  • 你是对的,有了这个改变,它现在可以工作了。
猜你喜欢
  • 2023-01-27
  • 2018-08-13
  • 1970-01-01
  • 2016-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多