1

I am creating one javascript library. In that I am using deferred methods for asynchronous call. But the thing is, if I log the output json object is not showing all the items. But if I expand the object then it is showing actual values. Look the below screenshot. enter image description here

In this console.log showing that subFolders object initially contains 0 elements, but if I expand the object then subFolders containing two elements. This output object is coming from multiple asynchronous calls. Following is my code

RESTQueries.getFilesFromFolders = function(){
    var execute = function(libraryName){
        var libraryItems={rootFolder:[],subFolders:[]};
        var deferred = $.Deferred();
        var _url = makeProperUrl();
        var itemsInRootFolder = getItemsFromFolder(libraryName,'files');
        itemsInRootFolder.then(function(data){
            var tempArray = [];
            if(typeof(data.d.results)!='undefined' && data.d.results.length>0)
            {

                for(var i =0;i<data.d.results.length;i++)
                {

                    tempArray.push({"name":data.d.results[i].Name});

                }
            }
            libraryItems.rootFolder.push(tempArray);
        }).then(function(){
            var subFolders = getItemsFromFolder(libraryName,'folders');
            subFolders.then(function(data){
                for(var item in data.d.results){
                    var fName = data.d.results[item].Name;
                    if(fName!='Forms')
                    {
                        var subFolderItems = getItemsFromFolder(libraryName+"/"+fName ,'files');
                        subFolderItems.then(function(subItems,link){
                            var actualFolderName = link.split("/")[1];
                            var tempArray={}; 
                            var tempArray2 = [];
                            for(var i=0;i<subItems.d.results.length;i++){
                                tempArray2.push({"name":subItems.d.results[i].Name});
                            }
                            tempArray[actualFolderName]=tempArray2;
                            tempArray2="";
                            libraryItems.subFolders.push(tempArray);                            
                        });
                    }
                }
            });         
        }).then(function(){
            deferred.resolve(libraryItems);
        });
        return deferred;
    };
    return{
        execute:execute
    }
}(); 

I am executing this function like,

RESTQueries.getFilesFromFolders.execute('HelpDocuments').then(function(data){
            console.log(data);
        },
        function(err){
            console.log(err);
        }); 

Why json object is behaving like this? Where I am doing mistake?

Mihir
  • 8,696
  • 18
  • 56
  • 87

2 Answers2

0

check if this code work for you

RESTQueries.getFilesFromFolders = function(){
    var execute = function(libraryName){
        var libraryItems={rootFolder:[],subFolders:[]};
        var deferred = $.Deferred();
        var _url = makeProperUrl();
        var itemsInRootFolder = getItemsFromFolder(libraryName,'files');
        itemsInRootFolder.then(function(data){
            var tempArray = [];
            if(typeof(data.d.results)!='undefined' && data.d.results.length>0)
            {

                for(var i =0;i<data.d.results.length;i++)
                {

                    tempArray.push({"name":data.d.results[i].Name});

                }
            }
            libraryItems.rootFolder.push(tempArray);
            

         var subFolders = getItemsFromFolder(libraryName,'folders');
                    subFolders.then(function(data){
                        for(var item in data.d.results){
                            var fName = data.d.results[item].Name;
                            if(fName!='Forms')
                            {
                                var subFolderItems = getItemsFromFolder(libraryName+"/"+fName ,'files');
                                subFolderItems.then(function(subItems,link){
                                    var actualFolderName = link.split("/")[1];
                                    var tempArray={}; 
                                    var tempArray2 = [];
                                    for(var i=0;i<subItems.d.results.length;i++){
                                        tempArray2.push({"name":subItems.d.results[i].Name});
                                    }
                                    tempArray[actualFolderName]=tempArray2;
                                    tempArray2="";
                                    libraryItems.subFolders.push(tempArray);   
                                    deferred.resolve(libraryItems);
                                });
                            }
                        }
                    });             
            
            
            
        });
        return deferred;
    };
    return{
        execute:execute
    }
}(); 
rjdmello
  • 865
  • 2
  • 9
  • 14
0

I didn't know a console could behave that way. Maybe it's better in other browsers.

We can't fix the console but we can fix the code, which needs some work to purge the Deferred anti-pattern and, more importantly, to acknowledge the asynchronism of the two inner getItemsFromFolder() calls.

The pattern isn't the simplest but you should end up with something like this :

RESTQueries.getFilesFromFolders = function(){
    var execute = function(libraryName) {
        return getItemsFromFolder(libraryName, 'files').then(function(data) {
            var tempArray;
            if(data.d && data.d.results) {
                tempArray = $.map(data.d.results, function(r) {
                    return { 'name': r.Name };
                });
            }
            return { rootFolder: [tempArray] || [] };
        }).then(function(libraryItems) {
            return getItemsFromFolder(libraryName, 'folders').then(function(data) {
                var promises = [];
                if(data.d && data.d.results) {
                    $.each(data.d.results, function(r) {
                        var fName = r.Name;
                        if(fName != 'Forms') {
                            promises.push(getItemsFromFolder(libraryName + "/" + fName, 'files').then(function(subItems, link) {
                                if(subItems.d && subItems.d.results) {
                                    var tempObj = {};
                                    tempObj[link.split("/")[1]] = $.map(subItems.d.results, function(r) {
                                        return { 'name': r.Name };
                                    });
                                    return tempObj;
                                }
                            }));
                        }
                    });
                }
                return $.when.apply(null, promises).then(function() {
                    return $.extend(libraryItems, {
                        subFolders: Array.prototype.slice.apply(arguments).filter(function(p) {
                            return !!p; //filter out any nulls
                        })
                    });
                });
            });
        });
    };
    return {
        execute:execute
    }
}();

I made a heap of mods and may well have made mistakes, so be prepared to do some debugging.

Community
  • 1
  • 1
Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
  • It is not only appearing in console. If i try find length like `console.log(data.subFolders.length);` then it is showing `0` instead of 2 – Mihir Nov 20 '14 at 08:51
  • That's not surprising when the length actually *is* zero. What is surprising is that the console should report length zero and length 2 simultaneously, in its expanded and unexpanded representations. – Roamer-1888 Nov 20 '14 at 09:26
  • And, with the code as it was in the question, data.subFolders.length should have been zero in both cases. The reason being that the asyncronisms of the inner `getItemsFromFolder()` calls are not taken into account in the resolution of the Deferred. You don't say whether or not you have tried my code. – Roamer-1888 Nov 20 '14 at 09:33
  • I am confusing to use your code. But I will try to implement this. I think you are not returning a `deferred` object right!! you are returning just json object – Mihir Nov 20 '14 at 10:23
  • In the `$.when()` function from where the `arguments` variable is coming? do you meant by `Array.prototype.slice.apply(promises)` ? – Mihir Nov 20 '14 at 10:54
  • No, look carefully. The first line of `.execute()` starts `return getItemsFromFolder(...`. That is a promise. After that is a complex set of .thens that modify that original promise. – Roamer-1888 Nov 20 '14 at 11:13
  • I use **[.apply()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)** twice. `$.when.apply(null, promises)` causes `$.when()` to operate on the array `promises`. `Array.prototype.slice.apply(arguments)` converts the array-like **[arguments](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments)** into a proper array. This all very standard stuff - more than beginners level but not particularly advanced. I suggest you follow the references and do some background reading. – Roamer-1888 Nov 20 '14 at 11:24
  • Understood. But the returned object is promise right! I used then function to it like `RESTQueries.getFilesFromFolders.execute('HelpDocuments').then(function(data){ console.log(data); });` but the console value is coming as `undefined` – Mihir Nov 20 '14 at 11:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/65282/discussion-between-roamer-1888-and-mihir). – Roamer-1888 Nov 20 '14 at 11:32