Um zu sehen, wie das schief gehen kann, drucken Sie console.log am Ende der Methode.
Dinge, die im Allgemeinen schief gehen können:
- Beliebige Reihenfolge.
- printFiles kann vor dem Drucken von Dateien ausgeführt werden.
- Schwache Leistung.
Diese sind nicht immer falsch, treten jedoch häufig in Standardanwendungsfällen auf.
Im Allgemeinen führt die Verwendung von forEach zu allen außer dem letzten. Es ruft jede Funktion auf, ohne auf die Funktion zu warten, was bedeutet, dass alle Funktionen gestartet und beendet werden, ohne auf das Beenden der Funktionen zu warten.
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()
Dies ist ein Beispiel in nativem JS, das die Ordnung beibehält, verhindert, dass die Funktion vorzeitig zurückkehrt, und theoretisch die optimale Leistung beibehält.
Dieser Wille:
- Initiieren Sie alle Dateilesevorgänge parallel.
- Behalten Sie die Reihenfolge bei, indem Sie mithilfe der Karte Dateinamen den Versprechungen zuordnen, auf die Sie warten müssen.
- Warten Sie auf jedes Versprechen in der vom Array festgelegten Reihenfolge.
Bei dieser Lösung wird die erste Datei angezeigt, sobald sie verfügbar ist, ohne darauf warten zu müssen, dass die anderen zuerst verfügbar sind.
Außerdem werden alle Dateien gleichzeitig geladen, anstatt warten zu müssen, bis die erste abgeschlossen ist, bevor der zweite Lesevorgang gestartet werden kann.
Der einzige Nachteil dieser und der Originalversion besteht darin, dass es schwieriger ist, Fehler zu behandeln, wenn mehrere Lesevorgänge gleichzeitig gestartet werden, da mehr Fehler gleichzeitig auftreten können.
Bei Versionen, die jeweils eine Datei lesen, wird der Fehler dann gestoppt, ohne dass Zeit damit verschwendet wird, weitere Dateien zu lesen. Selbst mit einem ausgeklügelten Stornierungssystem kann es schwierig sein, einen Fehler bei der ersten Datei zu vermeiden, aber auch die meisten anderen Dateien bereits zu lesen.
Die Leistung ist nicht immer vorhersehbar. Während viele Systeme mit parallelen Dateilesevorgängen schneller sind, bevorzugen einige sequentielle. Einige sind dynamisch und können sich unter Last verschieben. Optimierungen, die Latenz bieten, liefern bei starken Konflikten nicht immer einen guten Durchsatz.
In diesem Beispiel gibt es auch keine Fehlerbehandlung. Wenn etwas erfordert, dass sie entweder alle erfolgreich angezeigt werden oder gar nicht, wird dies nicht der Fall sein.
Es wird empfohlen, in jeder Phase eingehende Experimente mit console.log und gefälschten Lösungen zum Lesen von Dateien durchzuführen (stattdessen zufällige Verzögerung). Obwohl viele Lösungen in einfachen Fällen dasselbe zu tun scheinen, weisen alle subtile Unterschiede auf, die eine zusätzliche Prüfung erfordern, um sie herauszuquetschen.
Verwenden Sie dieses Modell, um den Unterschied zwischen Lösungen zu erkennen:
(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 ...
?