2016-07-11 8 views
2

私は次の関数の早い段階で返ってくることを知っています。再帰的約束を私の結果にどのようにつなげることができますか?約束と再帰でのファイルディレクトリの反復

私の目標は、ディレクトリとそのすべてのサブディレクトリのファイルのリストの配列を取得することです。配列は単一次元ですが、この例ではconcatを使用しています。

function iterate(body) { 
    return new Promise(function(resolve, reject){ 
     var list = []; 
     fs.readdir(body.path, function(error, list){ 
      list.forEach(function(file){ 
       file = path.resolve(body.path, file); 
       fs.stat(file, function(error, stat){ 
        console.log(file, stat.isDirectory()); 
        if(stat.isDirectory()) { 
         return iterate({path: file}) 
          .then(function(result){ 
           list.concat(result); 
          }) 
          .catch(reject); 
        } else { 
         list.push(file); 
        } 
       }) 
      }); 
      resolve(list); 
     }); 
    }); 
}; 
+0

http://stackoverflow.com/questionsここ


は、一般的なES6を使用したバージョンは約束です/ 29020722/recursive-promise-in-javascriptを読んで、 "return"を修正してください –

+0

あなたの関数の目標は何ですか?あなたは最終的に何を得ようとしていますか?完全なパスとディレクトリがないすべてのファイルの再帰的なリスト? – jfriend00

+0

@ jfriend00ディレクトリ内のファイルのリストとそのすべてのサブディレクトリを含む配列。配列は単一次元です。 – user2727195

答えて

8

コードに間違いが多数あります。部分的なリスト:

  1. .concat()のでそれだけでlist.concat(result)が実際に何もしない、新しい配列を返します。

  2. resolve()を同期して呼び出し、すべての非同期操作が完了するのを待っていません。

  3. いくつかのネストされた非同期コールバックの深い部分から再帰的に戻ろうとしています。あなたはそれをすることはできません。結果はどこにも戻ってこない。

fsモジュールの有名なバージョンを使用すると、このトンが使いやすくなります。私はそれを作成するために、ブルーバードを使用して、あなたはこれを行うことができます。

const path = require('path'); 
var Promise = require('bluebird'); 
const fs = Promise.promisifyAll(require('fs')); 

function iterate(dir) { 
    return fs.readdirAsync(dir).map(function(file) { 
     file = path.resolve(dir, file); 
     return fs.statAsync(file).then(function(stat) { 
      if (stat.isDirectory()) { 
       return iterate(file); 
      } else { 
       return file; 
      } 
     }) 
    }).then(function(results) { 
     // flatten the array of arrays 
     return Array.prototype.concat.apply([], results); 
    }); 
} 

注:私はそれがより一般的に便利ですので、ちょうど最初のパスを取るためにiterate()を変更しました。あなたは最初にbody.pathを渡すことができます。

const path = require('path'); 
const fs = require('fs'); 

fs.readdirAsync = function(dir) { 
    return new Promise(function(resolve, reject) { 
     fs.readdir(dir, function(err, list) { 
      if (err) { 
       reject(err); 
      } else { 
       resolve(list); 
      } 
     }); 
    }); 
} 

fs.statAsync = function(file) { 
    return new Promise(function(resolve, reject) { 
     fs.stat(file, function(err, stat) { 
      if (err) { 
       reject(err); 
      } else { 
       resolve(stat); 
      } 
     }); 
    }); 
} 


function iterate2(dir) { 
    return fs.readdirAsync(dir).then(function(list) { 
     return Promise.all(list.map(function(file) { 
      file = path.resolve(dir, file); 
      return fs.statAsync(file).then(function(stat) { 
       if (stat.isDirectory()) { 
        return iterate2(file); 
       } else { 
        return file; 
       } 
      }); 
     })); 
    }).then(function(results) { 
     // flatten the array of arrays 
     return Array.prototype.concat.apply([], results); 
    }); 
} 

iterate2(".").then(function(results) { 
    console.log(results); 
}); 

ここでカスタマイズ可能なフィルタ機能を追加したバージョンがあります:

function iterate2(dir, filterFn) { 
    // default filter function accepts all files 
    filterFn = filterFn || function() {return true;} 
    return fs.readdirAsync(dir).then(function(list) { 
     return Promise.all(list.map(function(file) { 
      file = path.resolve(dir, file); 
      return fs.statAsync(file).then(function(stat) { 
       if (stat.isDirectory()) { 
        return iterate2(file, filterFn); 
       } else { 
        return filterFn(file)? file : ""; 
       } 
      }); 
     })).then(function(results) { 
      return results.filter(function(f) { 
       return !!f; 
      }); 
     }); 
    }).then(function(results) { 
     // flatten the array of arrays 
     return Array.prototype.concat.apply([], results); 
    }); 
} 

// example usage 
iterate2(".", function(f) { 
    // filter out 
    return !(/(^|\/)\.[^\/\.]/g).test(f); 
}).then(function(results) { 
    console.log(results); 
}); 
+0

ブルーバードは使用できません。このプロジェクトは依存関係がなく、ネイティブの約束を使用しています。 – user2727195

+0

@ user2727195 - 私はあなたが手動で 'fs'操作を約束し、それらを使用することをお勧めします。これは、約束が多くの非同期操作を調整する方法だからです。 node.jsを使用し、外部モジュールを使用しないことは愚かなことです。それがnode.jsの主な強みなので、ホイールを再発明するのではなく、問題を解決する事前に構築されたモジュールを使用することができます。これが宿題でない限り...私はジェネリック版で作業することができますが、それ以上の作業はありません。 – jfriend00

+0

@ user2727195 - generic node.jsを使用し、アドオンライブラリを使用しないバージョンを追加しました。 – jfriend00

関連する問題