Ich stelle ein Beispiel zusammen, das zeigt, wie ein einfaches synchrones Node.js-Programm in eine asynchrone Version umgewandelt werden kann, die async/await verwendet. Es sollte mehrere Zwischenschritte geben, beginnend mit einer normalen Callback-basierten Version, gefolgt von einer, die zwei Callbacks verwendet, einen für den normalen (Auflösungs-) Fall und einen anderen für den Fehler- (Zurückweisungs-) Fall, was dann zu Versprechungen führen würde.Einen Rückruf im Node-Stil in zwei Callbacks aufteilen
Die Aufgabe jeder Version ist ein leerer Ordner Kopie zu schaffen (was möglicherweise bereits vorhanden sind und es könnte Dateien enthalten) und kopieren Sie alle Dateien (so genannte file1.txt und file2.txt) im Ordner orig dort. Wenn ein Fehler irgendwo auftritt, sollte er explizit abgefangen werden, auf die Konsole gedruckt werden und das Programm sollte nicht weiter fortfahren.
Die Version mit normalen Fehler-erste Rückrufe funktioniert gut, aber ich stieß auf ein Problem mit der Split-Callback-Version. Es kopiert nur Datei2.txt, aber nicht Datei1.txt. Hier
ist der Code verwende ich für die Transformation der fs-Funktionen:
const fs = require('fs');
fs.exists = function(path, callback) {
fs.stat(path, (err, stats) => {
if (err) {
callback(null, false);
} else {
callback(null, true);
}
});
};
function splitCallback(f) {
return (...params) => {
reject = params[params.length - 2];
resolve = params[params.length - 1];
params = params.slice(0, params.length - 2);
f(...params, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
};
}
const sfs = {};
const functionNames = ['exists', 'readdir', 'unlink', 'mkdir', 'readFile', 'writeFile'];
for (const functionName of functionNames) {
sfs[functionName] = splitCallback(fs[functionName].bind(fs));
}
und das ist das eigentliche Beispiel jene Funktionen:
function handleError(err) {
console.error(err);
}
function initCopyDirectory(callback) {
sfs.exists('copy', handleError, exists => {
if (exists) {
sfs.readdir('copy', handleError, filenames => {
let fileCount = filenames.length;
if (fileCount === 0) {
callback();
}
for (const filename of filenames) {
sfs.unlink(`copy/${filename}`, handleError,() => {
fileCount--;
if (fileCount === 0) {
callback();
}
});
}
});
} else {
sfs.mkdir('copy', handleError,() => callback);
}
});
}
function copyFiles() {
// sfs.readdir('orig', handleError, filenames => {
// for (const filename of filenames) {
// console.log(filename);
// sfs.readFile(`orig/${filename}`, handleError, data => {
// console.log('reading', filename);
// sfs.writeFile(`copy/${filename}`, data, handleError,() => {
// console.log('writing', filename);
// });
// });
// }
// });
sfs.readdir('orig', handleError, filenames => {
for (const filename of filenames) {
fs.readFile(`orig/${filename}`, (err, data) => {
if (err) {
handleError(err);
} else {
sfs.writeFile(`copy/${filename}`, data, handleError,() => {});
}
});
}
});
}
function main() {
initCopyDirectory(copyFiles);
}
main();
Wie es hier geschrieben wird es richtig funktioniert (Node-Version 7.4.0 für Windows), aber wenn ich die Kommentare in der copyFiles-Funktion vertausche (wodurch readFile geändert wird), wird nur eine Datei kopiert und ich erhalte die folgende Ausgabe:
file1.txt
file2.txt
reading file2.txt
writing file2.txt
writing file2.txt
Was ist das Problem?
Das dachte ich auch zuerst, aber ich bekomme das gleiche Ergebnis hier. Und laut [this] (http://exploringjs.com/es6/ch_for-of.html#_iteration-variables-const-declarations-versus-var-declarations) sollte ich eine neue Bindung für const-deklarierte Variablen in a bekommen for-of-Schleife in jeder Iteration. – Ignavia
@Ignavia was meinst du mit "eine frische Bindung". Die Verwendung von const ändert nicht die Tatsache, dass Sie die Bindung in asynchronen Funktionen innerhalb der for-Schleife nicht beibehalten können, die immer schneller als jede asynchrone Funktion ist. – AllTheTime
Verwenden Sie Ihr einfaches Beispiel in leicht veränderter Form: const a = [1,2,3, 4,5,6,7,8,9,10]; für (var i von a) { setTimeout (Funktion() { console.log (i); }, 100); } erzeugt zehnmal 10 als Ausgabe, während const a = [1,2,3,4,5,6,7,8,9,10]; für (const i von a) { setTimeout (Funktion {) { console.log (i); }, 100); } erzeugt die Zahlen von 1 bis 10. Es gibt eine besser formatierte Version unter dem Link im ersten Kommentar. – Ignavia