简体   繁体   中英

Newbie question about JavaScript promises and “then” statements

I'm fairly new to JavaScript, and I'm finding the concept of promises and "then" statements really hard to pin down. I'm working on a website using Firebase, and I'm trying to get user data from the database. Here's what I have at the moment:

// Function that fetches a user's data from the database.
getUserData = function(uid) {
  var database = firebase.firestore();
  var docRef = database.collection('users').doc(uid);

  var userData = docRef.get().then(function(doc) {
    if (doc.exists) {
      return doc.data();
    } else {
      console.log("User does not exist.");
      return null;
    }
  }).catch(function(error) {
    console.log("Error getting document:", error);
  });

  return userData;
}

Currently, this function returns a Promise object. When I log the object to the console, it says that the promise status is resolved and its value is the value of doc.data(). What I really want is to pass the value of doc.data() back up the "chain" to the getUserData function so that I can return and use it elsewhere. Is there a simple way to do this? I've tried to find a way to get the "value" of a Promise out of the object itself, but I've found nothing, and so far I have failed to find any other way to do what I want.

I'm sure it's a lot simpler than it seems, and I feel like an idiot for asking this sort of thing, but I've been searching for a couple of hours and none of the explanations I've found are helping. I would greatly appreciate any advice. Thanks!

Edit: Solved! Thanks for the help, everyone! Just in case this helps someone in the future who stumbles upon it, I'm leaving my final (working) code here. Unfortunately there's no way to call it from a synchronous function, but it ended up being good enough for my purposes:

// Function that fetches a user's data from the database.
async function getUserData(uid) {
  var database = firebase.firestore();
  var docRef = database.collection('users').doc(uid);

  var doc = await docRef.get();
  if (doc.exists) {
    return doc.data();
  } else {
    console.log("User does not exist.");
    return null;
  }
}

First you must understand that Promise are mainly used for asynchronous operation, and they do not store the value UNTIL the asynchronous operation is resolved. Promises to not expose any "get" method to retrieve directly their value but only a then method to execute a callback once the promise is resolved. Thus, with Promise you always need to "wait" for it to have resolved to read the value.

Now, you have two choices :

The first is to use the old way of then() and catch() .

You make your function return a Promise (like you did) and where you call your function, you can use then to execute a callback with your result.

getUserData("anId").then((userData) => console.log('the async result is' + userData))

You can also use catch to handle the error :

getUserData("anId")
.then((userData) => console.log('the async result is' + userData))
.catch((error) => console.error('wooopsie : ' + error))

As for the "new" way of doing things, you can use the async and await keywords of JS to handle your Promises.

Basically, a function declared async will always return a Promise and will define a context allowing to use the await keyword. And await will allow you to write your Promise handling just like synchronous code.

async function(){
const userData = await getUserData("anId");
console.log('the async result is' + userData);

Finally, if you need error handling, you will need to wrap the await instruction with a try-catch.

Hope this helps.

The reason for using promises is that they make asynchronous code easier to work with. Unfortunately the code can still be a little tricky if you're not used to it. You're probably better off using async/await in most situations as it will be easier to work with and also probably easier to understand:

async function getUserData(uid) {
  var database = firebase.firestore();
  var docRef = database.collection('users').doc(uid);
  var doc = await docRef.get();
  if(doc.exists)
    return doc.data();
  return null;
}

This is how you would use it:

// code to execute before
getUserData(uid).then(userData => {
  if(userData) {
  // code to execute after
  }
  else console.log("User does not exist.");
}).catch(error => {
  console.log("Error getting document:", error);
});

Alternatively (Async/Await):

async function doSomething(uid) {
  // code to execute before
  const userData = await getUserData(uid);
  // code to execute after
}

Async/Await with custom error handling:

async function doSomething(uid) {
  // code to execute before
  try {
    const userData = await getUserData(uid);
    if(userData) {
    // code to execute after
    }
    else console.log("User does not exist.");
  }
  catch(error) {
    console.log("Error:", error);
  }
}

为了从promise获得价值,您需要使用.then ,因此在您的情况下,要在调用getUserData的行中获取数据,您需要使用相同的构造( getUserData.then((data) => {})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM