【问题标题】:Deferred object not containing exact values in json object延迟对象不包含 json 对象中的确切值
【发布时间】:2015-01-16 19:57:21
【问题描述】:

我正在创建一个 JavaScript 库。因为我使用延迟方法进行异步调用。 但问题是,如果我记录输出 json 对象并没有显示所有项目。但是,如果我扩展对象,那么它会显示实际值。看下面的截图。

在这个console.log 中显示 subFolders 对象最初包含 0 个元素,但如果我展开该对象,则 subFolders 包含两个元素。此输出对象来自多个异步调用。以下是我的代码

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
    }
}(); 

我正在执行这个函数,

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

为什么 json 对象的行为是这样的?我在哪里做错了?

【问题讨论】:

    标签: jquery json jquery-deferred


    【解决方案1】:

    检查此代码是否适合您

    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
        }
    }(); 

    【讨论】:

    • 之前我也尝试过这种方式。结果没有变化
    【解决方案2】:

    我不知道控制台会这样。也许在其他浏览器上会更好。

    我们无法修复控制台,但我们可以修复代码,这需要一些工作来清除 Deferred anti-pattern,更重要的是,要确认两个内部 getItemsFromFolder() 调用的异步性。

    这个模式不是最简单的,但你应该得到这样的结果:

    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
        }
    }();
    

    我做了一堆模组,很可能犯了错误,所以准备做一些调试吧。

    【讨论】:

    • 它不仅出现在控制台中。如果我尝试查找像 console.log(data.subFolders.length); 这样的长度,那么它会显示 0 而不是 2
    • 当长度实际为零时,这并不奇怪。令人惊讶的是,控制台应该同时报告长度 0 和长度 2,在其展开和未展开的表示中。
    • 而且,使用问题中的代码,data.subFolders.length 在两种情况下都应该为零。原因是内部 getItemsFromFolder() 调用的异步在 Deferred 的解析中没有考虑在内。你没有说你有没有试过我的代码。
    • 我对使用您的代码感到困惑。但我会尝试实现这一点。我认为您没有返回deferred 对象!你只返回 json 对象
    • $.when() 函数中arguments 变量来自哪里?你是指Array.prototype.slice.apply(promises) 吗?
    猜你喜欢
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多