У вас здесь возникает ряд проблем - как с тем, как вы используете Firebase, как с вашими действиями в Google, так и с тем, как вы используете Javascript.Некоторые из этих проблем заключаются лишь в том, что вы могли бы делать вещи лучше и эффективнее, в то время как другие вызывают реальные проблемы.
Доступ к значениям в структуре в JavaScript
Первая проблема заключается в том, что allHighscores.users.userId.highscore
означает «В объекте с именем« allHighscores »получить свойство с именем« users », в результате чего получить свойство с именем« userId »».Но нет свойства с именем «userId» - есть просто набор свойств, названных по имени.
Возможно, вы хотели что-то более похожее на allHighscores.users[userId].highscore
, что означает «В объекте с именем« allHighscores », получитесвойство с именем 'users', в результате которого получают свойство, названное значением 'userId' ".
Но если в нем тысячи или сотни тысяч записей, это займет много времени.памяти.И займет много времени, чтобы получить от Firebase.Разве не было бы лучше, если бы вы только что извлекли одну запись непосредственно из Firebase?
Две проблемы с Firebase
Сверху вам, вероятно, следует просто извлечь одну запись изFirebase, а не вся таблица, а затем поиск одной записи, которую вы хотите.В Firebase это означает, что вы получаете ссылку на путь нужных вам данных, а затем запрашиваете значение.
Чтобы указать желаемый путь, вы можете сделать что-то вроде
var userRef = database.ref("highscores/users").child(userId);
var userScoreRef = userRef.child( "highscore" );
(Вы, конечно, можете поместить их в одно утверждение. Я разбил их вот так для ясности.)
Однако, получив справку, вы хотите прочитать данные, которые находятся по этой ссылке.У вас есть две проблемы:
Вы используете метод on()
, который выбирает значение один раз, но затем также устанавливает обратный вызов, который будет вызываться при каждом обновлении счета.Возможно, вам последнее не нужно, поэтому вы можете использовать метод once()
, чтобы получить значение один раз.
У вас есть функция обратного вызова для получения значения (что хорошо, поскольку это асинхронная операция, и это традиционный способ обработки асинхронных операций в Javascript), но вы возвращаете значение вне этого обратного вызова.Таким образом, вы всегда возвращаете пустое значение.
Это говорит о том, что вам нужно также сделать fetchHighScoreByUserId()
асинхронной функцией, и способ, которым мы должны сделать это сейчас, это вернутьОбещание.Это Обещание будет преобразовано в фактическое значение после завершения асинхронной функции.К счастью, библиотека Firebase может возвращать Promise, и мы можем получить его значение как часть предложения .then()
в ответе, поэтому мы можем многое упростить.(Я настоятельно рекомендую вам прочитать «Обещания» в Javascript и узнать, как их использовать.) Это может выглядеть примерно так:
return userScoreRef.once("value")
.then( function(scoreSnapshot){
var score = scoreSnapshot.val();
return score;
} );
Асинхронные функции и действия в Google
В обработчике намерений у вас проблема, аналогичная описанной выше.Вызов fetchHighScoreByUserId()
является асинхронным, поэтому он не завершает работу (или не возвращает значение) к тому времени, когда вы вызываете conv.ask()
или не возвращаетесь из функции.AoG нужно знать, чтобы дождаться завершения асинхронного вызова.Как это может сделать это?Обещания снова!
Обработчики намерений AoG должны вернуть Обещание, если в этом задействован вызов asyc.
Поскольку измененный fetchHighScoreByUserId()
возвращает Обещание, мы воспользуемся этим,Мы также установим наш ответ в .then()
части цепочки Promise.Это может выглядеть примерно так:
app.intent('get-highscore', (conv) => {
return fetchHighscoreByUserId(conv.user.id)
.then( function(highScore){
conv.ask(`Your highest score is ${highScore}. Do you want to play again?`);
} );
});
Здесь два аспекта:
Вам нужно использовать обратные символы "` "для определения строки, если вы пытаетесьиспользуйте $ {highScore} вот так.
Фраза «Скажи продолжить, если хочешь играть снова».очень плохой голосовой пользовательский интерфейс.Лучше прямо спросить, хотят ли они играть снова.