どのようにして問題が発生するかを確認するには、メソッドの最後にconsole.logを出力します。
一般的にうまくいかないことがあるもの:
- 任意の順序。
- printFilesは、ファイルを印刷する前に実行を終了できます。
- 業績不振。
これらは常に間違っているわけではありませんが、標準的なユースケースで頻繁に見られます。
通常、forEachを使用すると、最後以外のすべてになります。関数を待たずに各関数を呼び出します。つまり、すべての関数が開始するように指示し、関数が終了するのを待たずに終了します。
import fs from 'fs-promise'
async function printFiles () {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'))
for(const file of files)
console.log(await file)
}
printFiles()
これは、順序を保持し、関数が時期尚早に戻るのを防ぎ、理論的には最適なパフォーマンスを維持するネイティブJSの例です。
この意志:
- すべてのファイル読み取りを開始して、並行して実行します。
- mapを使用して順序を維持し、ファイル名を待機する約束にマップします。
- 配列で定義された順序で各プロミスを待ちます。
このソリューションでは、最初のファイルは、他のファイルが最初に利用可能になるのを待たずに、利用可能になるとすぐに表示されます。
また、2番目のファイルの読み取りを開始する前に、最初のファイルが完了するのを待つ必要がなく、すべてのファイルを同時にロードします。
これと元のバージョンの唯一の欠点は、一度に複数の読み取りが開始された場合、一度に発生する可能性のあるエラーが増えるため、エラーの処理がより困難になることです。
一度にファイルを読み取るバージョンでは、ファイルを読み取ろうとする時間を無駄にすることなく、失敗時に停止します。精巧なキャンセルシステムがあっても、最初のファイルで失敗するのを避けるのは難しいかもしれませんが、他のほとんどのファイルもすでに読み取っています。
パフォーマンスは常に予測できるとは限りません。多くのシステムは並列ファイル読み取りでより高速になりますが、シーケンシャルを好むシステムもあります。一部は動的であり、負荷がかかるとシフトする可能性があります。レイテンシを提供する最適化では、激しい競合下で常に良好なスループットが得られるとは限りません。
その例にはエラー処理もありません。何かがそれらをすべて正常に表示するか、まったく表示しないようにする必要がある場合、それはそれを行いません。
各段階でconsole.logを使用して詳細な実験を行うことをお勧めします。偽のファイル読み取りソリューション(ランダムな遅延)。多くの解決策は単純なケースでも同じことをするように見えますが、すべては微妙な違いがあり、絞り出すために特別な精査が必要です。
このモックを使用して、ソリューション間の違いを確認します。
(async () => {
const start = +new Date();
const mock = () => {
return {
fs: {readFile: file => new Promise((resolve, reject) => {
// Instead of this just make three files and try each timing arrangement.
// IE, all same, [100, 200, 300], [300, 200, 100], [100, 300, 200], etc.
const time = Math.round(100 + Math.random() * 4900);
console.log(`Read of ${file} started at ${new Date() - start} and will take ${time}ms.`)
setTimeout(() => {
// Bonus material here if random reject instead.
console.log(`Read of ${file} finished, resolving promise at ${new Date() - start}.`);
resolve(file);
}, time);
})},
console: {log: file => console.log(`Console Log of ${file} finished at ${new Date() - start}.`)},
getFilePaths: () => ['A', 'B', 'C', 'D', 'E']
};
};
const printFiles = (({fs, console, getFilePaths}) => {
return async function() {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'));
for(const file of files)
console.log(await file);
};
})(mock());
console.log(`Running at ${new Date() - start}`);
await printFiles();
console.log(`Finished running at ${new Date() - start}`);
})();
for ... of ...
か?