JS递归地构建对象 [英] JS build object recursively

查看:133
本文介绍了JS递归地构建对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用nodeJS构建文件结构索引。我正在使用fs.readir函数来迭代文件,这很好。我的问题是下降到目录结构并返回具有正确结构的完整对象。

I am attempting to build a file-structure index using nodeJS. I'm using the fs.readir function to iterate the files, which works fine. My problem is descending into the directory structure and returning a full object with the correct structure.

我有一个名为identify的简单函数,当给定文件名myfile.txt时会返回一个对象{name:myfile,输入:txt} ,这将解释下面函数的这一部分......

I have a simple function named identify which, when given file name "myfile.txt" will return an object {name: "myfile", type: "txt"}, which will explain that part of the function below...

我的问题是当我将索引器运行到me变量时没有返回任何内容。但是,console.log(results)行确实返回。这让我很困惑。

My problem is that nothing is being returned when I run the indexer into the "me" variable. The console.log(results) line does return, however. This leaves me quite confused.

任何帮助将不胜感激!

Any help would be greatly appreciated!

indexer = 
    function(directory){     
        Self.indexleft++;
        var results = {};
        Self.client.readdir(directory, function(err,fileLst){
            if(err){ return; }
            for(var count=0; count < fileLst.length; count++){
                var ident = identify(fileLst[count]);
                if(ident.type = 'dir'){
                    var descendant = (directory !== '') ? 
                        directory + '\\' + ident.name : ident.name;
                    ident.children = indexer(descendant);
                                }
                    //directory = (directory.split('\\').pop());
                    results[ident.name] = ident;
                 }
                 console.log(results);
                 return results;
             });
         }
         var me = indexer(''); console.log(me);

:
我实际上现在有一些工作,虽然不是很好我喜欢优雅。以下是我的所作所为。如果有人对优化有任何建议我很乐意听到它!

: I've actually got something working now, though it's not quite as elegant as I'd like. Below is what I did. If anyone has a suggestion on optimizing I'd be happy to hear it!!

最新(工作)代码:

var events = require('events'),
    event = new events.EventEmitter(),
setToValue = function(obj, value, path) {
    path = path.split('\\');
    for (i = 0; i < path.length - 1; i++)
        obj = obj[path[i]];
    obj[path[i]] = value;
},
identify = function(file){
    var split = file.split('.'),
        type = (split.length > 1) ? split.pop() : 'dir',
        filename = split.join('.');
    return { name: filename, type: type };
};
Indexer = function(cli,dir,callback){  
    this.client = cli; // File reading client
    this.startDir = dir; // Starting directory
    this.results = {}; // Result object
    this.running = 0; // How many itterations of start() are running
    this.start(dir); // Start indexing
    this.monit(); // Start never returns anything, monit() checks ever 5 seconds and will fire callback if 0 itterations are running.
    this.callbackDone = false; // Checks whether the callback has already been fired. Important in case of interval staggering
    this.cb = callback;
}
Indexer.prototype = {
    start: function(directory){        
        var Self = this;
        Self.running++;
        Self.client.readdir(directory, function(err,fileLst){
            if(err){ Self.running--; return; }
            for(var count=0; count < fileLst.length; count++){
                var ident = identify(fileLst[count]);
                var descendant = (directory !== '') ? directory + '\\' + ident.name : ident.name;
                if(ident.type === 'dir'){                
                    Self.start(descendant);
                }
                setToValue(Self.results, ident, descendant);
            }
            Self.running--;
            console.log('running' + Self.running);
        });
    },
    monit: function(){
        var Self = this;
        Self.intervalA = setInterval(function(){
            if(Self.running < 1){                
                if(!Self.callbackDone){ 
                    this.callbackDone=true; 
                    Self.cb(Self.results);
                }
                clearInterval(Self.intervalA);

            }
        }, 5000)
    }
}

var ix = new Indexer(Self.client,'',function(res){
                        console.log("Index Complete!");
                        fs.writeFile(path.join(Self.localLibBase,'/index.json'), JSON.stringify(res), (err)=> {
                            console.log("FileWrite Complete!");
                        });
                    });

返回对象结构示例:

{
    "Applications" : {
        "name" : "Applications",
        "type" : "dir",
        "Microsoft Exchange Server 2007" : {
            "name" : "Microsoft Exchange Server 2007",
            "type" : "dir",
            "Microsoft Exchange Server 2007 SP1" : {
                "name" : "Microsoft Exchange Server 2007 SP1",
                "type" : "iso"
            }
        }
    }
}


推荐答案

结果只能异步提供,所以你试图过早输出结果。内部代码仅在稍后执行。

The result is only available asynchronously, so you are trying to output the result too soon. The inner code is only executed later.

您可以通过多种方式解决此问题。使用异步代码的一个非常好的解决方案是使用 promises

You can solve this in many ways. A very nice solution to working with asynchronous code is using promises.

当你有一个递归的电话时,你也必须用承诺解决这个问题。

As you have a recursive call, you'll have to resolve that with promises too.

注意:注意你在与dir的比较中有一个错误:你分配而不是比较。

NB: Note you had a bug in the comparison with "dir": you assigned instead of comparing.

以下是你的代码的样子:

Here is how your code would look:

var indexer = function(directory) {
    // return a promise object
    return new Promise(function (resolve, reject) {
        Self.indexleft++;
        var results = {};
        Self.client.readdir(directory, function(err,fileLst){
            if(err) { 
                reject(); // promise is rejected
                return;
            }
            // "Iterate" over file list asyonchronously
            (function nextFile(fileList) {
                if (!fileList.length) {
                    resolve(results);  // promise is resolved
                    return;
                }
                var file = fileLst.shift(); // shop off first file
                var ident = identify(file); 
                results[ident.name] = ident;
                if(ident.type === 'dir'){ // There was a bug here: equal sign!
                    var descendant = directory !== '' 
                            ? directory + '\\' + ident.name : ident.name;
                    // recursively call indexer: it is again a promise!        
                    indexer(descendant).then(function (result) {
                        ident.children = result;
                        // recursively continue with next file from list
                        nextFile(fileList);
                    });
                } else {
                    nextFile(fileLst);
                }
            })(fileLst); // start first iteration with full list
        });
    });
};

// Call as a promise. Result is passed async to callback. 
indexer('').then(function(me) {
    console.log(me);
});

我为你的外部参考做了一些虚拟函数,使这个代码段工作:

I made some dummy functions for your external references to make this snippet work:

// Below code added to mimic the external references -- can be ignored
var filesystem = [
    "",
    "images",
    "images\\photo.png",
    "images\\backup",
    "images\\backup\\old_photo.png",
    "images\\backup\\removed_pic.jpg",
    "images\\panorama.jpg",
    "docs",
    "docs\\essay.doc",
    "readme.txt",
];

var Self = {
    indexLeft: 0,
    client: {
        readdir: function (directory, callback) {
            var list = filesystem.filter( path => 
                    path.indexOf(directory) == 0 
                    && path.split('\\').length == directory.split('\\').length + (directory!=='')
                    && path !== directory
            ).map ( path => path.split('\\').pop() );
            setTimeout(callback.bind(null, 0, list), 100);
        }
    }
}

function identify(item) {
    return {
        name: item,
        type: item.indexOf('.') > -1 ? 'file' : 'dir'
    };
}
// Above code added to mimic the external references -- can be ignored

var indexer = function(directory) {
    // return a promise object
    return new Promise(function (resolve, reject) {
        Self.indexleft++;
        var results = {};
        Self.client.readdir(directory, function(err,fileLst){
            if(err) { 
                reject(); // promise is rejected
                return;
            }
            // "Iterate" over file list asyonchronously
            (function nextFile(fileList) {
                if (!fileList.length) {
                    resolve(results);  // promise is resolved
                    return;
                }
                var file = fileLst.shift(); // shop off first file
                var ident = identify(file); 
                results[ident.name] = ident;
                if(ident.type === 'dir'){ // There was a bug here: equal sign!
                    var descendant = directory !== '' 
                            ? directory + '\\' + ident.name : ident.name;
                    // recursively call indexer: it is again a promise!        
                    indexer(descendant).then(function (result) {
                        ident.children = result;
                        // recursively continue with next file from list
                        nextFile(fileList);
                    });
                } else {
                    nextFile(fileLst);
                }
            })(fileLst); // start first iteration with full list
        });
    });
};

// Call as a promise. Result is passed async to callback. 
indexer('').then(function(me) {
    console.log(me);
});

这篇关于JS递归地构建对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆