1

意味

File#createDirectoriesFromJSON (json, cb);

json:JSONオブジェクト。

cb:関数。パラメータ:error(Error)、created(ブール値、少なくとも1つのディレクトリが作成されている場合はtrue)。

Fileクラスに_path、ディレクトリのパスを含むという名前のプロパティが含まれているとします。


利用方法

var json = {
    b: {
        c: {
            d: {},
            e: {}
        },
        f: {}
    },
    g: {
        h: {}
    }
};

//this._path = "."
new File (".").createDirectoriesFromJSON (json, function (error, created){
    console.log (created); //Prints: true

    //callback binded to the File instance (to "this"). Hint: cb = cb.bind (this)
    this.createDirectoriesFromJSON (json, function (error, created){
        console.log (created); //Prints: false (no directory has been created)
    });
});


結果

下 "。" jsonオブジェクトに表示されるディレクトリツリーが作成されました。

./b/c/d
./b/c/e
./b/f
./b/g/h


実装

これは私がasync.jsなしで持っているものです:

File.prototype.createDirectoriesFromJSON = function (json, cb){
    cb = cb.bind (this);

    var created = false;
    var exit = false;

    var mkdir = function (path, currentJson, callback){
        var keys = Object.keys (currentJson);
        var len = keys.length;
        var done = 0;

        if (len === 0) return callback (null);

        for (var i=0; i<len; i++){
            (function (key, i){
                var dir = PATH.join (path, key);
                FS.mkdir (dir, function (mkdirError){
                    exit = len - 1 === i;

                    if (mkdirError && mkdirError.code !== "EEXIST"){
                        callback (mkdirError);
                        return;
                    }else if (!mkdirError){
                        created = true;
                    }

                    mkdir (dir, currentJson[key], function (error){
                        if (error) return callback (error);
                        done++;
                        if (done === len){
                            callback (null);
                        }
                    });
                });
            })(keys[i], i);
        }
    };

    var errors = [];

    mkdir (this._path, json, function (error){
        if (error) errors.push (error);
        if (exit){
            errors = errors.length === 0 ? null : errors;
            cb (errors, errors ? false : created);
        }
    });
};

好奇心のために、async.jsを使用して関数を書き直したいと思います。ここでの問題は、関数が再帰的で並列であるということです。たとえば、「b」フォルダは「g」と並行して作成されます。「b/c」と「b/f」、「b / c/d」と「b/c/e」も同様です。

4

2 に答える 2

4

私の試み:

var _path  = require('path');
var _fs    = require('fs');
var _async = require('async');

function File() {
    this._path = __dirname + '/test';
}

File.prototype.createDirectoriesFromJSON = function(json, cb) {
    var created = [], errors  = [];

    function iterator(path, currentJson, key, fn){
        var dir = _path.join(path, key);

        _fs.mkdir(dir, function(mkdirError) {

            if(mkdirError && mkdirError.code !== "EEXIST") {
                errors.push(mkdirError);
            } else if(!mkdirError) {
                created.push(dir);
            }

            mkdir(dir, currentJson[key], fn);
        });
    }

    function mkdir(path, currentJson, callback) {
        var keys = Object.keys(currentJson);

        if(keys.length === 0) return callback(null);

        _async.forEach(keys, iterator.bind(this, path, currentJson), callback);
    }

    mkdir(this._path, json, cb.bind(this, errors, created));
};


new File().createDirectoriesFromJSON({
    b: {
        c: {
            d: {},
            e: {}
        },
        f: {}
    },
    g: {
        h: {}
    }
}, function(errors, successes) {
    // errors is an array of errors
    // successes is an array of successful directory creation
    console.log.apply(console, arguments);
});

テスト済み:

$ rm -rf test/* && node test.js && tree test

[] [ '/Users/fg/Desktop/test/b',
  '/Users/fg/Desktop/test/g',
  '/Users/fg/Desktop/test/b/c',
  '/Users/fg/Desktop/test/b/f',
  '/Users/fg/Desktop/test/g/h',
  '/Users/fg/Desktop/test/b/c/d',
  '/Users/fg/Desktop/test/b/c/e' ] null
test
|-- b
|   |-- c
|   |   |-- d
|   |   `-- e
|   `-- f
`-- g
    `-- h

7 directories, 0 files

ノート:

  • errors.push(mkdirError);ディレクトリを作成できなかったことを意味するのでreturn fn(null);、このブランチからのディレクトリ作成を停止するためにディレクトリを追加できます。
  • cb常にである3番目の引数を受け取りますnull
  • この種のタスクにはレンチ を使用するか、非同期mkdirpをサブスタックすることをお勧めします。.mkdirSyncRecursive()

[更新] mkdirpとlodash(またはアンダースコア)を使用すると、コードがさらに明確になります。

var _path   = require('path');
var _fs     = require('fs');

var _async  = require('async');
var _mkdirp = require('mkdirp');
var _       = require('lodash'); // or underscore

function File() {
    this._path = __dirname + '/test';
}

File.prototype.flattenJSON = function(json){
    function walk(path, o, dir){
        var subDirs = Object.keys(o[dir]);
        path +=  '/' + dir;

        if(subDirs.length === 0){
            return path;
        }

        return subDirs.map(walk.bind(null, path, o[dir]));
    }

    return _.flatten(Object.keys(json).map(walk.bind(null, this._path, json)));
};

File.prototype.createDirectoriesFromJSON = function(json, cb) {
    var paths   = this.flattenJSON(json)
    ,   created = []
    ,   errors  = [];

    function iterator(path, fn){
        _mkdirp(path, function(mkdirError) {

            if(mkdirError && mkdirError.code !== "EEXIST") {
                errors.push(mkdirError);
            } else if(!mkdirError) {
                created.push(path);
            }

            return fn(null);
        });
    }

    _async.forEach(paths, iterator, cb.bind(this, errors, created));
};


new File().createDirectoriesFromJSON({
    b: {
        c: {
            d: {},
            e: {}
        },
        f: {}
    },
    g: {
        h: {}
    }
}, function(errors, successes) {
    // errors is an array of error
    // successes is an array of successful directory creation
    console.log.apply(console, arguments);
});

テスト済み:

$ rm -rf test/* && node test2.js && tree test

[] [ '/Users/fg/Desktop/test/b/f',
  '/Users/fg/Desktop/test/g/h',
  '/Users/fg/Desktop/test/b/c/d',
  '/Users/fg/Desktop/test/b/c/e' ] null
test
|-- b
|   |-- c
|   |   |-- d
|   |   `-- e
|   `-- f
`-- g
    `-- h

7 directories, 0 files

ノート:

  • iterator部分機能アプリケーションを使用して削除できますが、アンダースコア/ lodashは左から右への部分のみをサポートしているため、別のライブラリで削除する必要はありませんでした。
于 2012-10-28T09:56:26.087 に答える
0

それが最善の解決策であるかどうかはわかりませんが、過去に追加の「モニター」タイプのオブジェクトを作成することでこれを解決しました。つまり、初期化を次のようなものに変更します。

var monitor = {
    var init = function(json, cb) {
        this.outerDirLength = Object.keys (currentJson);
        this.processedOuterDirs = 0; //track 'report progress'  calls
        this.completedOuterDirs = 0; //'report progress' calls with no errors = success
        this.errors = [];
        this.finishedCallback = cb;
    }
    var reportProgress = function(error) {
        this.processedOuterDirs++;
        if (error) this.errors.push(error);
        else this.completedOuterDirs++;
        if (this.isComplete()) this.finish();
    }
    var finish = function () {
        var errors = this.errors.length === 0 ? null : this.errors;
        this.finishedCallback(errors, errors ? false : this.completedOuterDirs);
    }
    var isComplete = function() {
        return this.processedOuterDirs == this.outerDirLength;
    }
};
monitor.init(json, cb);
if (monitor.isComplete()) {
    //handle case of JSON with zero definitions
    monitor.finish();
    return;
}
mkdir (this._path, json, function (error){
    monitor.reportProgress(error);
});

上記はテストされていない(またはテストコンパイルされていない)が、アイデアが得られるはずです... mkdirを真に非同期にする場合は、mkdirへの各呼び出しの開始時に上記を変更してください。作成するdirの数を計算し、モニターで予想されるターゲットをインクリメントしてから、作成されるたびにモニターを更新しました。

于 2012-10-27T11:25:02.303 に答える