Dialogflow - 使用 async/await 从数据库中读取
Dialogflow - Reading from database using async/await
这是我第一次使用 async/await。我在 dialogflow 意图内的数据库请求上下文中使用它时遇到问题。我该如何修复我的代码?
会发生什么?
当我尝试 运行 使用我的后端时 - 这就是我得到的:"Webhook call failed. Error: Request timeout."
我怀疑什么?
我的辅助函数 getTextResponse() 等待 airtable 的 return 值,但从未得到它。
我想做什么?
- "GetDatabaseField-Intent" 被触发
- 它在内部通过 getTextResponse()
向我的 airtable 数据库发送请求
- 因为我使用"await"函数会在继续之前等待结果
- getTextResponse() 将 return "returnData";因此 var 结果将填充 "returnData"
- getTextResponse() 已完成;因此将使用它的 return 值
创建响应
'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 块处理该错误。
这是我第一次使用 async/await。我在 dialogflow 意图内的数据库请求上下文中使用它时遇到问题。我该如何修复我的代码?
会发生什么?
当我尝试 运行 使用我的后端时 - 这就是我得到的:"Webhook call failed. Error: Request timeout."
我怀疑什么?
我的辅助函数 getTextResponse() 等待 airtable 的 return 值,但从未得到它。
我想做什么?
- "GetDatabaseField-Intent" 被触发
- 它在内部通过 getTextResponse() 向我的 airtable 数据库发送请求
- 因为我使用"await"函数会在继续之前等待结果
- getTextResponse() 将 return "returnData";因此 var 结果将填充 "returnData"
- getTextResponse() 已完成;因此将使用它的 return 值 创建响应
'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 块处理该错误。