2016-11-26 5 views
0

私は2つの約束をしています。 sample.txtファイルを読み取るファイルと、/books/フォルダーからすべてのファイルを読み取るファイル2番目の約束は、readFilesと呼ばれる関数を使用しています。この関数は、ファイル名を取り、それを使って各ファイルを調べます。すべての約束は準備ができているときthen内のコードを実行する必要がありますPromise.allはPromise拒否のために決して起動しません

const p1 = new Promise((resolve, reject) => { 
    fs.readdir(__dirname + '/books/', (err, archives) => { 
    // archives = [ 'archive1.txt', 'archive2.txt'] 
    readFiles(archives, result => { 
     if (archives.length === result.length) resolve(result) 
     else reject(result) 
    }) 
    }) 
}) 

const p2 = new Promise((resolve, reject) => { 
    fs.readFile('sample.txt', 'utf-8', (err, sample) => { 
    resolve(sample) 
    }) 
}) 

Promise.all([p1, p2]).then(values => { 
    console.log('v:', values) 
}).catch(reason => { 
    console.log('reason:', reason) 
}) 

function readFiles (archives, callback) { 
    const result = [] 
    archives.forEach(archive => { 
    fs.readFile(__dirname + '/books/' + archive, 'utf-8', (err, data) => { 
     result.push(data) 
     callback(result) 
    }) 
    }) 
} 

をしかし、Promise.allは常に拒否されます:

理由:[ 'アーカイブ1 \ n' は]

何私は間違っている?

+1

Promise.allは何ですか?(ニッチ:Promise.all *はトリガーされています; *最初の拒否で拒否するか、*すべての受諾を待って受け入れます) – user2864740

+1

実際の/実際の質問は 'else reject(result)'の回りを回っています。対応するif節がなぜ真でないのかを示します。 – user2864740

答えて

3

約束はワンショットデバイスです。彼らが拒否されたり解決されたりすると、彼らの状態は変わることはありません。このことを念頭に置いて、readFiles()、読み込むすべてのファイルのためのコールバックを呼び出して、あなたが拒否またはそのコールバックが呼び出されるたびに解決するが、あなたはそれを使用している方法は、あなたがチェック:

if (archives.length === result.length) 

は真ではありませんどの最初の1つにして、あなたは拒否します。その約束が拒否されると、その状態は変わることができません。それ以降のコールバックコールではreject()がコールされ、最後のコールではresolve()がコールされますが、状態が長くなってからまたはresolve()への最初のコールだけが実際に何もしません。他は単に無視されます。したがって、p1は常に拒否されるため、p1を使用するPromise.all()は常に拒否します。

readFiles()を変更する必要があります。すべてのファイルで完了したコールバックを一度だけ呼び出すか、すべてのファイルを読み込んだときに解決する単一の約束を返すように変更するか、コールバックの使い方を変更します。それが初めて呼び出されたときにあなたは拒否しません。一般的に


あなたが約束を使用するつもりなら、あなたはかなりのミックスコールバックとの約束よりも、どこでも最低レベルでpromisifyと(エラー伝播のための特定の)約束の利点を利用したいです。そのために、私はお勧めしたい:より深いレベルを行くともfs.readdir()をpromisifying、

fs.readFileP = function(fname, encoding) { 
    return new Promise(function(resolve, reject) { 
     fs.readFile(fname, encoding, function(err, data) { 
      if (err) return reject(err); 
      resolve(data); 
     }); 
    }); 
} 

function readFiles(archives, encoding, callback) { 
    return Promise.all(archives.map(function(file) { 
     return fs.readFileP(file, encoding); 
    })); 
} 

をそれとも、あなたはこれを取得したい:

// helper functions 
fs.readdirP = function(dir) { 
    return new Promise(function(resolve, reject) { 
     fs.readdir(dir, function(err, files) { 
      if (err) return reject(err); 
      resolve(files); 
     }); 
    }); 
} 

fs.readFileP = function(fname, encoding) { 
    return new Promise(function(resolve, reject) { 
     fs.readFile(fname, encoding, function(err, data) { 
      if (err) return reject(err); 
      resolve(data); 
     }); 
    }); 
} 

function readFiles(archives, encoding) { 
    encoding = encoding || 'utf8'; 
    return Promise.all(archives.map(function(file) { 
     return fs.readFileP(file, encoding); 
    })); 
} 

// actual logic for your operation 
const p1 = fs.readdirP(__dirname + '/books/').then(readFiles); 
const p2 = fs.readFileP('sample.txt', 'utf-8'); 

Promise.all([p1, p2]).then(values => { 
    console.log('v:', values); 
}).catch(reason => { 
    console.log('reason:', reason); 
}); 

をあなたが作るBluebird promise libraryを使用している場合一度にモジュール全体を約束することは容易であり、Promiseフロー制御を管理するためのいくつかの余分な機能を持っています。

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

const p1 = fs.readdirAsync(__dirname + '/books/').then(files => { 
    return Promise.map(archives, file => { 
     return fs.readFileAsync(file, 'utf8'); 
    }); 
}); 
const p2 = fs.readFileAsync('sample.txt', 'utf-8'); 

Promise.all([p1, p2]).then(values => { 
    console.log('v:', values); 
}).catch(reason => { 
    console.log('reason:', reason); 
}); 

コードのこのブロックでは、Promise.promisifyAll()コードの行は、接尾辞を持つfsモジュールのすべてのメソッドの有名なバージョンを作成します。ここでは、fs.readFileAsync()fs.readdirAsync()を使用しているので、約束をすべて使用することができます。

+0

お寄せいただきありがとうございます!私は明日それを試してみるよ。だから、これらの2つの関数はすべて私のコードを置き換えると思われますか? – alex

+0

@alex - すべてのコードを置き換えるものではありません。 'p1'コードを変更する必要があります。 – jfriend00

+0

@alex - 私は私の答えに多くの情報とオプションを追加しました。 – jfriend00

関連する問題