Dialogflow - 使用 async/await 从数据库中读取

Dialogflow - Reading from database using async/await

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

会发生什么?

当我尝试 运行 使用我的后端时 - 这就是我得到的:"Webhook call failed. Error: Request timeout."

我怀疑什么?

我的辅助函数 getTextResponse() 等待 airtable 的 return 值,但从未得到它。

我想做什么?

  1. "GetDatabaseField-Intent" 被触发
  2. 它在内部通过 getTextResponse()
  3. 向我的 airtable 数据库发送请求
  4. 因为我使用"await"函数会在继续之前等待结果
  5. getTextResponse() 将 return "returnData";因此 var 结果将填充 "returnData"
  6. getTextResponse() 已完成;因此将使用它的 return 值
  7. 创建响应
'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);

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

让我请你再次 Google 关于 JavaScript 承诺,并根据之前的评论再次研究它们,看看是否能解决这个难题。

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

看起来 var result = await getTextResponse(...) 调用也不正确。您已定义 getTextResponse() 接受两个参数,但您传递了三个参数(前两个,加上一个匿名箭头函数)。但是这个额外的功能永远不会 used/referenced.

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

我不知道你正在使用的 API 的详细信息,但如果 API 已经支持 promises,那么你应该可以这样做:

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

...

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