0

I want to extract all child-Folders and child-Docs querying a node-js Service, which every time it is called, returns an array of such items. I do not know the depth fo the folders-tree so I want to recursively call a function that in the end will return an array that will contain all child-folders and child-docs, starting from a list of root-Folders. Each folder is identified by a folder id.

So I have made a "recPromise(fId)" which returns a promise. Inside, this function calls recursively the recFun(folderId).I start invoking the "recPromise(fId)" from a rootFolder so once all root-promises are resolved I can go on.

rootFolders.map( folderOfRootlevel =>{
    var folderContentPromise = recPromise(folderOfRootlevel.id);
    folderContentPromises.push(folderContentPromise);
})

$q.all(folderContentPromises)
   .then(function(folderContent) { 
      // Do stuff with results.
}

function recPromise(fId){
    return new Promise((resolve, reject) => {
    var items = [];
    function recFun( folderId) {   // asynchronous recursive function
        function handleFolderContent( asyncResult) {  // process async result and decide what to do
        items.push(asyncResult);
        //Now I am in a leaf-node, no child-Folders exist so I return
        if (asyncResult.data.childFolders.length === 0){
              return items;
        }
         else {   
            //child_folders exist. So call again recFun() for every child-Folder     
            for(var item of asyncResult.data.childFolders)  {
               return  recFun(item._id); 
             }                              
        }
    }
    // This is the service that returns the array of child-Folders and child-Docs
    return NodeJSService.ListFolders(folderId).then(handleFolderContent);
   }
  resolve(recFun(fId));
 })
}


It works almost as expected except the loop inside else, where I call again recFun(). 
The NodeJSService will return an array of sub-Folders so I wish to call recfun() for every sub-Folder.
Now, I only get the result of the 1st sub-Folder of the loop, 
which makes sense since I have a return statement there. 
If I remove the return statement and call like this "recFun(item._id);" 
then it breaks the $q.all().
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Sep 24 '19 at 16:56
  • FYI, this loop `for(var item of asyncResult.data.childFolders)` is pointless because you `return` on the first iteration. Probably you need to remove the `return`. – jfriend00 Sep 25 '19 at 06:32
  • @jfriend00 You are right, it does not make sense to return of the first loop. I understand I have to remove the return statement there, but if I do it I can not get all promise responses in q.all() – Konstantinos Cheilakos Sep 25 '19 at 07:02

1 Answers1

0

Finally, I decided to remove the Promise wrapper function and make use of async-await.

        var items = [];
        (async() => {
            for(var item of rootFolders)  {
                await recFun(item.id)
            }
            // Do stuff with items
           // go on form here..
        })()

        function listFolders(folderId) { 
            return new Promise( function( resolve, reject) {
                resolve(FolderService.ListFolders(folderId));  
            })
        }

        async function recFun(folderId) {
            var foldersResponse= await listFolders(folderId);
            items.push(foldersResponse);
            if (foldersResponse.data.childFolders.length === 0){
                return items ;
            }
            else {        
                for(var item of foldersResponse.data.childFolders)  {
                    await recFun(item._id); 
                }    
            }

        }