1

这是我第一次使用 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);
4

2 回答 2

1

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

让我再次请你谷歌关于 JavaScript Promises 并根据刚刚发表的评论再次研究它们,看看是否能解决这个难题。

于 2019-06-03T19:47:51.597 回答
1

正如@Kolban 指出的那样,您没有接受或拒绝您在getTextResponse().

看起来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 块来处理该错误。

于 2019-06-03T20:16:45.467 回答