Thomas David Kehoe
Thomas David Kehoe

Reputation: 10930

How to get this for...of loop to stop and wait before going on? (JavaScript async/await with Firestore listener)

This function processes an array of words. If it finds a word in our dictionary it goes on to the next word. If it doesn't find the word in our dictionary it writes a word request to our Firestore database. Then it sets up a listener that listens for the word response to be written to the Firebase database. When the response is written the listener is detached. This takes about two seconds. This code iterates through the array of words without waiting for the word response. How do I tell it to wait for the word response before going on to the next word?

$scope.requestWords = function() {

  async function processWordRequests() {
    for (let word of $scope.wordsArray) {
      console.log(word);
      var doc = await firebase.firestore().collection('Dictionaries').doc($scope.longLanguage).collection("Words").doc(word).get()
      if (doc.data() === undefined) {
        console.log("Didn't find " + word + " in L2 dictionary.");

        await firebase.firestore().collection('Users').doc($scope.user.uid).collection($scope.longLanguage).doc('Word_Request').set({
          word: word,
          requestOrigin: $scope.longLanguage + ':' + $scope.movieTitle + ':' + $scope.clipInMovieModel
        })
        console.log("Requested " + word);

        await firebase.firestore().collection('Users').doc($scope.user.uid).collection($scope.longLanguage).doc('Word_Response').onSnapshot(function(doc) {
          console.log("Listening for response...");
          if (doc.data().word === word) {
            console.log(word + " added to L2 dictionary.");
            firebase.firestore().collection('Users').doc($scope.user.uid).collection($scope.longLanguage).doc('Word_Response')
            .onSnapshot(function (){
              console.log("Listener unsubscribed.")
              // How do I make it wait here before going on to the next word?
              return;
            });
          }
          else {
            console.log("Still listening...")
          }
        });

      } else {
        console.log("Found " + word + " in L2 dictionary.");
      }
    }
  }

  processWordRequests();
};

Upvotes: 0

Views: 324

Answers (1)

Incognito
Incognito

Reputation: 20765

You need to use promises or promisify your code.

You have this line of code:

    await firebase.firestore().collection('Users').doc($scope.user.uid).collection($scope.longLanguage).doc('Word_Response').onSnapshot(function(doc) {

Which way over on the right side (please use line breaks to improve readability) you have .onSnapshot(function(doc) { which I don't know for sure but I'm going to guess doesn't return a promise, so you can't await on it.

Instead you can wrap it with a promise like...

await new Promise((resolve, reject)=> {
    firebase.firestore().collection('Users').doc($scope.user.uid).collection($scope.longLanguage).doc('Word_Response').onSnapshot(function(doc) {
    ...
    resolve("value-to-return-to-await").
    ...
});

You can learn more about promises with this self-contained training course: https://github.com/stevekane/promise-it-wont-hurt

Upvotes: 1

Related Questions