1

I've tied myself up in knots trying to return from a function which uses chained asynchronous node-fetches. Please help since I'm not familiar with promises and the like

In the function MessgSums() I am initially fetching a list of conversations which works fine.

convlst = fetch(url+'/conversations', settings)

I then use the result of this fetch to perform a loop of fetches for all conversations

for(i=0;i<dat.length;++i){
convDetails = fetch(url + '/conversations/'+dat[i].id+'/messages')
            .then(res => res.json())
            .then((msgDetails)=>{

This too works fine.

I next populate an object with the data returned by 2 fetch calls as shown below and then push the constructed object into an array. This too works fine.

convDetails = fetch(url + '/conversations/'+dat[i].id+'/messages')
            .then(res => res.json())
            .then((msgDetails)=>{

                    var msgobj = {
                        id:msgDetails[0].conversation_id,
                        latest_message : {
                            body:msgDetails[0].body,
                            from_user:{},
                            created_at:msgDetails[0].created_at
                        }
                    }                    

                    fetch(url + '/users/'+msgDetails[0].from_user_id)
                    .then(res => res.json())
                    .then((user) => {                        
                     
                        msgobj.latest_message.from_user = {
                            id:user.username,
                            avatar_url : user.avatar_url
                        } 

                        //push to array
                        allmsgs.push(msgobj);
                })
            
        });

    };

    return allmsgs; 
});

At the very end of the outer then() I return the array allmgs.

I next call the function but get an undefined error most probably because the asynchronous call has not completed.

var msgarr = MessgSumms(); //how do i call MessgSums and capture the returned array allmsgs
console.log(msgarr); //gives undefined

How do I capture the populated array once it has been fully constructed and returned by MessgSums()??

Here is what I've coded

const express = require('express');
const fetch = require('node-fetch');


const app = express();
app.use(express.json());
app.use(express.urlencoded({extended:true}));


const portnum = process.env.PORT || 3000;
app.listen(portnum, () => {
    console.log("Server is listening on port "+portnum);
    
}); 



//--------------------------- Urls for App Center REST functions-----------------------//
var url = 'https://someurl/api';
let settings = {method:"get"};
var convDetails;
var allmsgs = [];
var convlst;

//----------------------------------------------------------------------------------//



function MessgSumms() {

    convlst = fetch(url+'/conversations', settings)
    .then(res => res.json())
    .then((conversationsList) => {    
        
    return conversationsList;
    });


    convlst.then(dat => {

        for(i=0;i<dat.length;++i){
            
            convDetails = fetch(url + '/conversations/'+dat[i].id+'/messages')
            .then(res => res.json())
            .then((msgDetails)=>{
                    //console.log("CID : " +msgDetails[0].conversation_id);            
                    //console.log("MBody : " +msgDetails[0].body);
                    //console.log("CDate : " +msgDetails[0].created_at);            
                    var msgobj = {
                        id:msgDetails[0].conversation_id,
                        latest_message : {
                            body:msgDetails[0].body,
                            from_user:{},
                            created_at:msgDetails[0].created_at
                        }
                    }
                    //console.log("From : " +msgDetails[0].from_user_id);
                

                    fetch(url + '/users/'+msgDetails[0].from_user_id)
                    .then(res => res.json())
                    .then((user) => {
                    
                        //console.log('UName : '+user.username);
                        //console.log('UAvatar : '+user.avatar_url);
                        //console.log("--------------------------------------------------");
                        msgobj.latest_message.from_user = {
                            id:user.username,
                            avatar_url : user.avatar_url
                        }                    
                        console.log("Object Starts")
                        console.log("------------------------------------")
                        console.log("ID :" + msgobj.id);
                        console.log("Latest Msg Body :" + msgobj.latest_message.body);
                        console.log("From User :" + msgobj.latest_message.from_user.id);
                        console.log("User Avatar :" + msgobj.latest_message.from_user.avatar_url);
                        console.log("Created at :" + msgobj.latest_message.created_at);

                        //push to array
                        allmsgs.push(msgobj);
                    })
                
            });

        };

        return allmsgs; 
    });

}  



var msgarr = MessgSumms(); //how do i call MessgSums and capture the returned array allmsgs
console.log(msgarr); //gives undefined
pcodex
  • 1,812
  • 15
  • 16

1 Answers1

0

You can promisify your MessgSumms function and return the 'allmsgs' array by resolving it.

   function MessgSumms() {
     return new Promise((resolve,reject)=>{
      convlst = fetch(url+'/conversations', settings)
      .then(res => res.json())
      .then((conversationsList) => {    
    
      return conversationsList;
      });


      convlst.then(dat => {

       for(i=0;i<dat.length;++i){
        
        convDetails = fetch(url + '/conversations/'+dat[i].id+'/messages')
        .then(res => res.json())
        .then((msgDetails)=>{
                //console.log("CID : " +msgDetails[0].conversation_id);            
                //console.log("MBody : " +msgDetails[0].body);
                //console.log("CDate : " +msgDetails[0].created_at);            
                var msgobj = {
                    id:msgDetails[0].conversation_id,
                    latest_message : {
                        body:msgDetails[0].body,
                        from_user:{},
                        created_at:msgDetails[0].created_at
                    }
                }
                //console.log("From : " +msgDetails[0].from_user_id);
            

                fetch(url + '/users/'+msgDetails[0].from_user_id)
                .then(res => res.json())
                .then((user) => {
                
                    //console.log('UName : '+user.username);
                    //console.log('UAvatar : '+user.avatar_url);
                    //console.log("--------------------------------------------------");
                    msgobj.latest_message.from_user = {
                        id:user.username,
                        avatar_url : user.avatar_url
                    }                    
                    console.log("Object Starts")
                    console.log("------------------------------------")
                    console.log("ID :" + msgobj.id);
                    console.log("Latest Msg Body :" + msgobj.latest_message.body);
                    console.log("From User :" + msgobj.latest_message.from_user.id);
                    console.log("User Avatar :" + msgobj.latest_message.from_user.avatar_url);
                    console.log("Created at :" + msgobj.latest_message.created_at);

                    //push to array
                    allmsgs.push(msgobj);
                })
            
        });

    };

    resolve(allmsgs); 
   });
 });

}  



var msgarr = await MessgSumms(); //you need to await it, so call it inside a async function
console.log(msgarr);
Naveen Chahar
  • 561
  • 3
  • 10
  • Thanks. I'm aware of the async/await approach. My question is how can it be done using Promises/then() – pcodex Nov 18 '20 at 00:22