Проблема с обновлением переменной в Vue. js - PullRequest
0 голосов
/ 22 января 2020

Я создаю веб-приложение с Vue. js (это первый раз, когда я его использую). Приложение представляет собой многопользовательскую викторину в реальном времени, в которой каждый пользователь должен выбрать роль и ответить на вопросы, связанные с его ролью. Я использую коллекцию в облачной базе данных firestore для хранения вопросов, связанных с каждой ролью, и ответов, связанных с каждым вопросом. Более того, каждый ответ характеризуется полем «nextQuestion», которое содержит идентификатор следующего вопроса для визуализации, полем «nextUser», которое содержит идентификатор следующего пользователя, с которым связан этот новый вопрос (эти поля используются в запросах к выберите следующий вопрос и его возможные ответы) и булево поле «default», которое указывает, если оно истинно, ответ, выбранный в том случае, если пользователь не отвечает на вопрос в течение установленного времени (другие - в поле, указывающее текст ответ). Я получаю вопросы и ответы с запросом, чтобы визуализировать их в веб-приложении. Моя проблема связана с ситуацией, когда пользователь не отвечает на вопрос в течение установленного времени (между тем, если пользователь выбирает ответ в течение установленного времени, у меня нет проблем). Когда время ответа истекает, я вызываю эту функцию:

CountTerminated: function () {    

  if(this.optionSelected == false){   //optionSelected is a component variable that informs if a user has selected or not an answer

    this.onNotSelectedAnswer(this.getDefaultAnswer())

  }

  else{
              this.onClickButtonConfirm()  //function called if the user selects an answer within the set time
      }  

}

Функция getDefaultAnswer () получает поля (среди которых "nextUser" и "nextQuestion") ответа по умолчанию, связанного с текущим вопросом (через запрос) и вернуть их через переменную:

 getDefaultAnswer(){

            var data 
            db.collection("Utenti").doc(this.userId).collection("Domande").doc(this.questionId).collection("Risposte").where("default","==",true).get().then(querySnapshot =>{

                querySnapshot.forEach(doc=>{


                data = doc.data()

              })
            })

            return data

          },

функция onNotSelectedAnswer (data) в основном принимает на вход значение, возвращаемое getDefaultAnswer (), назначает «данные» переменной компонента answerId и он обновляет значение переменной компонента «userId» (которая сообщает о роли пользователя, который должен ответить на текущий вопрос), значение переменной компонента «questionId» (которая содержит идентификатор текущего вопроса) и значение questionValue (содержащее текст текущего вопроса) с использованием функций setUserId (), setQuestionId (), setQuestionValue ()

onNotSelectedAnswer: function(data){


            if(this.userChoice == this.userId){

              this.answerId = data


            this.setUserId(this.answerId.nextUser)
            this.setQuestionId(this.answerId.nextQuestion)
            this.setQuestionValue()

            this.optionSelected = false
            this.answers=[]
            this.isActive = ""
            this.getAnswers()   //function used to query  (using updated values of userId and questionId variable) the DB to obtain a question and its related possible answers
            var a = this.channel.trigger('client-confirmEvent',{ user:  this.userId, question : this.questionId, questionval: this.questionValue})   
            console.log(a)


            }

 }

Проблема связана с тем, что в функции onNotSelectedAnswer () answerId является "неопределенным" вместо того, чтобы содержать результат qu и поэтому данные, которые я буду использовать, чтобы загрузить новый вопрос. Я не понимаю, в чём заключается ошибка, надеюсь, вы мне поможете.

1 Ответ

0 голосов
/ 23 января 2020

Проблема в том, что запрос Firestore является асинхронным, но вы не ждете ответа, прежде чем продолжить. По сути, у вас есть следующее:

getDefaultAnswer () {
  var data 

  // This next bit is asynchronous
  db.doLotsOfStuff().then(querySnapshot => {
    // This callback won't have been called by the time the outer function returns
    querySnapshot.forEach(doc => {
      data = doc.data()
    })
  })

  return data
},

Асинхронный вызов Firestore будет выполняться в фоновом режиме. Между тем остальная часть кода в getDefaultAnswer будет продолжать работать синхронно.

Таким образом, в тот момент, когда код достигает return data, ни один из кодов внутри обратного вызова then не будет запущен. Вы можете подтвердить это, введя некоторые записи в консоли, чтобы увидеть, в каком порядке выполняется код.

Использование then для работы с асинхронным кодом является функцией Promises. Если вы еще не знакомы с Обещаниями, вам следует изучить их подробно, прежде чем идти дальше. Вот одно из многих доступных руководств:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Суть в том, что вы не можете заставить метод getDefaultAnswer ждать асинхронного действия для полный. Вместо этого вы можете вернуть подходящее обещание, а затем дождаться разрешения этого обещания, прежде чем позвонить onNotSelectedAnswer. Это может выглядеть примерно так:

getDefaultAnswer () {
  // We return the Promise chain from getDefaultAnswer
  return db.doLotsOfStuff().then(querySnapshot => {
    var data = null

    // I have assumed that forEach is synchronous
    querySnapshot.forEach(doc => {
      data = doc.data()
    })

    // This resolves the Promise to the value of data
    return data
  })
},

Важно понимать, что метод getDefaultAnswer не пытается вернуть значение данных. Вместо этого он возвращает Обещание, которое будет resolve равным значению данных.

В пределах CountTerminated вы затем будете использовать его следующим образом:

this.getDefaultAnswer().then(defaultAnswer => {
  this.onNotSelectedAnswer(defaultAnswer)
})

или, если вы предпочитаете:

this.getDefaultAnswer().then(this.onNotSelectedAnswer)

Последнее является более кратким, но не обязательно более ясным.

Вы также можете написать его, используя async / await, но я бы не советовал пытаться использовать async / await пока у вас не будет solid гр asp того, как работают Обещания. Хотя async / await может быть очень полезным для исправления кода, это всего лишь небольшая оболочка для Обещаний, и вам нужно понимать Обещания для устранения любых проблем.

Код, который я предложил выше, должен работать, но есть задержка, пока он ожидает завершения асинхронного запроса. В этой задержке могут произойти вещи, например, пользователь может нажать на кнопку. Это может привести к дальнейшим проблемам.

Альтернативой может быть загрузка ответа по умолчанию намного раньше. Не ждите, пока он вам действительно не понадобится. Возможно, загрузите его, как только появится вопрос. Сохраните результат где-нибудь доступным, возможно, в подходящем data свойстве, чтобы оно было доступно, как только оно вам понадобится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...