我尝试使用ActionsSDK,Firebase功能和Firebase Firestore构建ActionsOnGoogle应用。
我建立了一个有意图的实现。启动Actions App时的mainIntent和当用户从mainIntent回答问题时的answerIntent。从firestore数据库获取mainIntent中的文本,并询问包含文本的用户是否正常工作。但是然后在函数内部从数据库数组中包装新数据得到填充。执行此函数后,数组为空。
这是我的代码:
function answerIntent(app){
console.log('DEBUG: answerIntent acsess');
console.log('DEBUG: ' + partAwnserRef);
var rawInput = app.getRawInput();
var answerCollection = db.collection(partAwnserRef);
var answers = answerCollection.get().then(collection => {
console.log('DEBUG: Collection size: ' + collection.size);
collection.forEach(document => {
if(document.exists){
console.log('DEBUG: document ID: ' + document.id + ' = ' + document.data());
answerDocumentArray.push(document);
console.log('DEBUG: ArraySize: ' + answerDocumentArray.length);
//HERE MY ARRAY WAS FILLED CORRECTLY
}
else{
console.log('DEBUG: Dokument existiert nicht;');
app.tell('Es liegt ein Fehler vor!');
}
});
})
.catch(err => {
console.log('DEBUG: Es ist ein Fehler aufgetretten ' + err);
app.tell('Es liegt ein Fehler vor!');
});
//HERE THE OUTPOT IN THE LOG SAY THE ARRAY IS EMPTY
console.log("DEBUG: lenght " + answerDocumentArray.length);
for(var i = 0; i < answerDocumentArray.length; i++){
var propertyNameArray = [];
for(var propertyName in answerDocumentArray[i]){
propertyNameArray.push(propertyName);
console.log('DEBUG: propertyName: ' + propertyName);
}
for(var j = 0; j < propertyNameArray.length; j++){
if(propertyNameArray[j].includes('answer')){
if(rawInput.includes(answerDocumentArray[i].propertyNameArray[j])){
app.tell(answerDocumentArray[i].propertyNameArray[j]);
}
else{
var inputPrompt = app.buildInputPrompt(false, 'Ich habe die leider nicht verstanden!', ['Kannst du deine Antwort wiederholen?']);
app.ask(inputPrompt);
}
}
}
}
};
当我查看firebase日志时,会看到我的自编码日志。我得到以下内容。第一次登录是最新的。
DEBUG:lenght 0
DEBUG:收藏规模:2
DEBUG:文件ID:answer1 = [object Object]
DEBUG:ArraySize:1
DEBUG:文件ID:answer2 = [object Object]
DEBUG:ArraySize:2
答案 0 :(得分:4)
你有两个问题,它们都从根本上涉及了解结果如何从你正在处理的内容中传回:
问题1:使用承诺
answerDocumentArray
行DEBUG: lenght
为空的原因是因为对answerCollection.get()
的调用实际上并未返回值。它返回一个JavaScript Promise对象,最终将解析为值。
然后,它会继续执行代码,代码中的下一行是调试行。
当它解析为这些值时,将调用then()
子句中的函数并开始处理返回的集合。但这可以在调试行之后的行之后执行。当函数完成时,它应该返回另一个Promise,其中任何结果都表明需要进一步评估的内容。 (在这种情况下 - 你没有返回任何东西,最终为空。)
你应该做的是拥有另一个then()
子句,该子句链接传递answerDocumentArray
的第一个并使用它。大致像这样:
var answers = answerCollection.get().then( collection =>{
console.log( 'DEBUG: Collection size: ' + collection.size );
collection.forEach( document =>{
if( document.exists
){
console.log( 'DEBUG: document ID: ' + document.id + ' = ' + document.data() );
answerDocumentArray.push( document );
console.log( 'DEBUG: ArraySize: ' + answerDocumentArray.length );
//HERE MY ARRAY WAS FILLED CORRECTLY
}
else{
console.log( 'DEBUG: Dokument existiert nicht;' );
app.tell( 'Es liegt ein Fehler vor!' );
}
} )
return Promise.resolve( answerDocumentArray );
;
} )
.then( answers => {
for( var i = 0; i < answers.length; i++ ){
// ... Do stuff with the answers here
}
})
.catch( err =>{
console.log( 'DEBUG: Es ist ein Fehler aufgetretten ' + err );
app.tell( 'Es liegt ein Fehler vor!' );
} )
;
(我可能已经破坏了关于Promises的解释,但是帮自己一个忙 - 学习JavaScript Promises。它们仍然很痛苦,但它们使得JavaScript回调世界更容易。)
但你对“做东西”部分的处理方式导致了第二个问题:
问题2:通过Google上的操作返回值
此代码块尝试在循环内向Google Assistant返回值(实际上,在双循环内部,但即使一个循环也足够糟糕)。
除非您只能保证一个结果,否则您将尝试多次调用app.ask()
或app.tell()
,假设您可以为符合条件的每个文档返回一个回复满足。
for( var j = 0; j < propertyNameArray.length; j++ ){
if( propertyNameArray[j].includes( 'answer' ) ){
if( rawInput.includes( answerDocumentArray[i].propertyNameArray[j] ) ){
app.tell( answerDocumentArray[i].propertyNameArray[j] );
}
else{
var inputPrompt = app.buildInputPrompt( false, 'Ich habe die leider nicht verstanden!', ['Kannst du deine Antwort wiederholen?'] );
app.ask( inputPrompt );
}
}
}
但是, Google上的操作无法正常运行。每次调用Intent时,您只能向用户发送单个响应。该响应必须位于单个ask()
或单个tell()
中。你不能多次打电话给他们。如果您尝试多次调用它,结果是未定义的,但最多只能获得第一个结果。 (最糟糕的是,它会崩溃。)
如果您需要返回多个结果,则需要在完成循环时收集它们,然后根据您收集的结果只说出一些内容。