最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - how do I assign a returned value from an async function to a variable - Stack Overflow

programmeradmin7浏览0评论

I am new to JavaScript and have been trying to read up a lot on why this is not working. Here is my code. I have also read a number of articles here on stack overflow but still feeling dense

Also if my title does not make sense, please suggest an edit

 listRef.listAll()
            .then(response => {
                let files = []  
                response.items.forEach(item => {
                    
                  var text
                  getText(item.name).then(res=>{text = res});
                    
                    const id = {uid: guid()}
                    const url = item.getDownloadURL().then(url => {return url} )
                    const gsurl = `gs://archivewebsite.appspot/${folder}/${item.name}`
                    files.push({...item, name:item.name, url, gsurl, id:id.uid, text})
                
                    });
                    this.files = files;
                  })
            .catch(error => console.log(error));


  async function getText(docID) {
        var docRef = firestore.collection("recipes").doc(docID);
        let doc = await docRef.get()
        if (doc.exists){
           return doc.data().text
         }
}

that code "works" in that it logs the response to the console but the text variable is a pending promise object.

I understand that async functions return a promise so when I call getText I need to use .then - what I am struggling with and have refactored this code a few times is this: how can I assign the value of doc.data().text to a variable to be used later in other words, how can var text be an actual string and not a promise object pending

Also for my own learning on javascript inside the async function if I replace

if (doc.exists){
           return doc.data().text
         }

with

 if (doc.exists){
           return Promise.resolve(doc.data().text)
         }

I get the same result in console.log - is this expected? is return simply short hand for the handler to resolve the promise?

I have also refactored this code to be non async and I get the same result where my var text is basically a pending promise and never the resolved data

Thanks for your help - also any articles to help explain this to me would be great! I have been going through courses on udemy but little confused by this right now

I am new to JavaScript and have been trying to read up a lot on why this is not working. Here is my code. I have also read a number of articles here on stack overflow but still feeling dense

Also if my title does not make sense, please suggest an edit

 listRef.listAll()
            .then(response => {
                let files = []  
                response.items.forEach(item => {
                    
                  var text
                  getText(item.name).then(res=>{text = res});
                    
                    const id = {uid: guid()}
                    const url = item.getDownloadURL().then(url => {return url} )
                    const gsurl = `gs://archivewebsite.appspot./${folder}/${item.name}`
                    files.push({...item, name:item.name, url, gsurl, id:id.uid, text})
                
                    });
                    this.files = files;
                  })
            .catch(error => console.log(error));


  async function getText(docID) {
        var docRef = firestore.collection("recipes").doc(docID);
        let doc = await docRef.get()
        if (doc.exists){
           return doc.data().text
         }
}

that code "works" in that it logs the response to the console but the text variable is a pending promise object.

I understand that async functions return a promise so when I call getText I need to use .then - what I am struggling with and have refactored this code a few times is this: how can I assign the value of doc.data().text to a variable to be used later in other words, how can var text be an actual string and not a promise object pending

Also for my own learning on javascript inside the async function if I replace

if (doc.exists){
           return doc.data().text
         }

with

 if (doc.exists){
           return Promise.resolve(doc.data().text)
         }

I get the same result in console.log - is this expected? is return simply short hand for the handler to resolve the promise?

I have also refactored this code to be non async and I get the same result where my var text is basically a pending promise and never the resolved data

Thanks for your help - also any articles to help explain this to me would be great! I have been going through courses on udemy but little confused by this right now

Share Improve this question edited Aug 20, 2020 at 3:07 Kevin asked Aug 20, 2020 at 2:31 KevinKevin 4339 silver badges21 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

Actually you are assigning the plete promise to the variable text

Replace

var text = getText(item.name).then(res=>console.log(res))

by

var text = await getText(item.name);

OR

var text
getText(item.name).then(res=>{text = res});

OK I worked with someone at work and found a solution - it was related to this post https://stackoverflow./a/37576787/5991792 I was using async function inside a for each loop

the refactored code is here

async function buildFiles(){
  let items = await listRef.listAll()
  let files = []
  for (const item of item.items){
    const text = await getText(item.name)
    const url = await item.getDownloadURL()
    const gsurl = `gs://archivewebsite.appspot./${folder}/${sermon.name}`
    files.push({...item, name:item.name, url, gsurl, text})  
}
return files
}


 async function getText(docID) {
        var docRef = firestore.collection("recipies").doc(docID);
        let doc = await docRef.get()
        if (doc.exists){return await doc.data().text}}



buildFiles().then(res=>this.files = res)

Thanks also to @cyqsimon and @Nav Kumar V

Of course text is going to be a Promise. Promise.then() always returns a Promise.

Consider this code:

function doA(n) {
  // do something here...
  console.log("A" + n);
}
asnyc function doB(n) {
  // do something here...
  console.log("B" + n);
}

doA(1);
doA(2);
doB(3); // async
doA(4);
doB(5); // async
doB(6); // async
doA(7);

What do you expect the output to be?

  • 1, 2, 4, and 7 will always be in order, because they are executed synchronously.
  • 3 will not ever print before 1 and 2. Likewise, 5 and 6 will not ever print before 1, 2, and 4.
  • However, 3, 5, and 6 can be printed in any order, because async functions do not guarantee execution order once created.
  • Also, 4 can print before 3. Likewise, 7 can print before 5 and 6.

Basically, think of async functions as a parallel task that runs independently (although not really; single thread JS only simulates this behavior). It can return (fulfill/reject) at any moment. For this reason, you cannot just simply assign a return value of an async function to a variable using synchronous code - the value is not guaranteed to be (and probably is not) available at the moment of synchronous execution.


Therefore you need to put all the code that requires the value of text to be set into the callback block of the Promise, something like this:

getText(item.name).then((text) => {
  // put everything that uses text here
});

This can of course lead to the infamous "callback hell", where you have layers inside layers of async callback. See http://callbackhell. for details and mitigation techniques.

async/await is just one of the newer ways to do the same thing: MDN has an excellent article here: https://developer.mozilla/en-US/docs/Learn/JavaScript/Asynchronous/Async_await

发布评论

评论列表(0)

  1. 暂无评论