【问题标题】:Dialogflow - Reading from database using async/awaitDialogflow - 使用异步/等待从数据库中读取
【发布时间】:2019-06-03 19:35:28
【问题描述】:

这是我第一次使用 async/await。我在对话流意图内的数据库请求上下文中使用它时遇到问题。如何修复我的代码?

会发生什么?

当我尝试使用我的后端运行时 - 这是我得到的:“Webhook 调用失败。错误:请求超时。”

我怀疑什么?

我的辅助函数 getTextResponse() 等待 airtable 的返回值,但永远不会得到它。

我想做什么?

  1. “GetDatabaseField-Intent”被触发
  2. 在它内部通过 getTextResponse() 向我的 airtable 数据库发送请求
  3. 因为我使用了“await”,所以函数会等待结果再继续
  4. getTextResponse() 将返回“returnData”;因此 var 结果将填充“returnData”
  5. getTextResponse() 已完成;因此将使用它的返回值创建响应
'use strict';

const {
  dialogflow
} = require('actions-on-google');

const functions = require('firebase-functions');
const app = dialogflow({debug: true});
const Airtable = require('airtable');
const base = new Airtable({apiKey: 'MyKey'}).base('MyBaseID');

///////////////////////////////
/// Helper function - reading Airtable fields.
const getTextResponse = (mySheet, myRecord) => {
    return new Promise((resolve, reject) => {
        // Function for airtable
        base(mySheet).find(myRecord, (err, returnData) => {
        if (err) {
            console.error(err);
            return; 
        }
        return returnData;
        });
    }       
)};

// Handle the Dialogflow intent.
app.intent('GetDatabaseField-Intent', async (conv) => {
  const sheetTrans = "NameOfSheet";
  const recordFirst = "ID_OF_RECORD";

  var result = await getTextResponse(sheetTrans, recordFirst, (callback) => {
    // parse the record => here in the callback
    myResponse = callback.fields.en;

  });
  conv.ask(myResponse);
});

// Set the DialogflowApp object to handle the HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);

【问题讨论】:

    标签: node.js async-await dialogflow-es actions-on-google airtable


    【解决方案1】:

    正如@Kolban 指出的那样,您没有接受或拒绝您在getTextResponse() 中创建的Promise。

    看起来var result = await getTextResponse(...) 调用也不正确。您已经定义了getTextResponse() 来接受两个参数,但是您传递了三个参数(前两个,加上一个匿名箭头函数)。但是这个额外的函数从未被使用/引用过。

    我通常会避免将显式 Promise 与 async/await 混合,并且绝对避免将 async/await 与传递回调混合。

    我不知道您正在使用的 API 的详细信息,但如果 API 已经支持 Promise,那么您应该可以执行以下操作:

    const getTextResponse = async (mySheet, myRecord) => {
        try {
            return await base(mySheet).find(myRecord)
        }
        catch(err) {
            console.error(err);
            return; 
        }
    )};
    
    ...
    
    app.intent('GetDatabaseField-Intent', async (conv) => {
      const sheetTrans = "NameOfSheet";
      const recordFirst = "ID_OF_RECORD";
    
      var result = await getTextResponse(sheetTrans, recordFirst)
      myResponse = result.fields.en;
      conv.ask(myResponse);
    });
    
    ...
    

    几乎所有基于 Promise 的库或 API 都可以与 async/await 一起使用,因为它们只是在底层使用 Promises。 await 之后的所有内容都成为一个回调,当等待的方法成功解析时调用该回调。任何不成功的解决方案都会引发 PromiseRejected 错误,您可以使用 try/catch 块来处理该错误。

    【讨论】:

    • 啊,成功了!您的解释对我来说是一个很好的起点,可以更多地了解 Promise。非常感谢,BrianHVB!
    【解决方案2】:

    看代码,看来你可能对 JavaScript Promises 有误解。当你创建一个 Promise 时,你会得到两个函数,称为 resolve 和 reject。在你的 Promise 代码的主体中(即将在未来某个时间完成的代码)。您必须调用resolve(returnData)reject(returnData)。如果你不调用任何一个,你的 Promise 将永远不会被实现。查看您的逻辑,您似乎执行了简单的返回,而没有调用解决或拒绝。

    让我再次请你谷歌上 JavaScript Promises 并再次研究它们与刚刚创建的 cmet 相关的内容,看看是否能解决这个难题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-02
      • 1970-01-01
      • 2021-07-07
      • 1970-01-01
      • 2019-07-29
      • 2020-10-03
      • 2022-07-06
      • 1970-01-01
      相关资源
      最近更新 更多