Ich möchte eine andere Lösung anbieten, die die Geschwindigkeit und Effizienz des Programmierparadigmas im Kern von Node nutzt: Ereignisse.
Alles, was Sie mit Versprechungen oder Modulen tun können, die zur Verwaltung der Flusskontrolle entwickelt wurden async
, kann mithilfe von Ereignissen und einer einfachen Zustandsmaschine erreicht werden, die meiner Meinung nach eine Methodik bietet, die möglicherweise einfacher zu verstehen ist als andere Optionen.
Angenommen, Sie möchten die Länge mehrerer Dateien parallel summieren:
const EventEmitter = require('events').EventEmitter;
// simple event-driven state machine
const sm = new EventEmitter();
// running state
let context={
tasks: 0, // number of total tasks
active: 0, // number of active tasks
results: [] // task results
};
const next = (result) => { // must be called when each task chain completes
if(result) { // preserve result of task chain
context.results.push(result);
}
// decrement the number of running tasks
context.active -= 1;
// when all tasks complete, trigger done state
if(!context.active) {
sm.emit('done');
}
};
// operational states
// start state - initializes context
sm.on('start', (paths) => {
const len=paths.length;
console.log(`start: beginning processing of ${len} paths`);
context.tasks = len; // total number of tasks
context.active = len; // number of active tasks
sm.emit('forEachPath', paths); // go to next state
});
// start processing of each path
sm.on('forEachPath', (paths)=>{
console.log(`forEachPath: starting ${paths.length} process chains`);
paths.forEach((path) => sm.emit('readPath', path));
});
// read contents from path
sm.on('readPath', (path) => {
console.log(` readPath: ${path}`);
fs.readFile(path,(err,buf) => {
if(err) {
sm.emit('error',err);
return;
}
sm.emit('processContent', buf.toString(), path);
});
});
// compute length of path contents
sm.on('processContent', (str, path) => {
console.log(` processContent: ${path}`);
next(str.length);
});
// when processing is complete
sm.on('done', () => {
const total = context.results.reduce((sum,n) => sum + n);
console.log(`The total of ${context.tasks} files is ${total}`);
});
// error state
sm.on('error', (err) => { throw err; });
// ======================================================
// start processing - ok, let's go
// ======================================================
sm.emit('start', ['file1','file2','file3','file4']);
Welches wird ausgegeben:
Start: Beginn der Verarbeitung von 4 Pfaden
forEachPath: Starten von 4 Prozessketten
readPath: file1
readPath: file2
processContent: file1
readPath: file3
processContent: file2
processContent: file3
readPath: file4
processContent: file4
Die Gesamtzahl von 4 Dateien beträgt 4021
Beachten Sie, dass die Reihenfolge der Prozesskettenaufgaben von der Systemlast abhängt.
Sie können sich den Programmablauf folgendermaßen vorstellen:
start -> forEachPath - + -> readPath 1 -> processContent 1 - + -> done
+ -> readFile 2 -> processContent 2 - +
+ -> readFile 3 -> processContent 3 - +
+ -> readFile 4 -> processContent 4 - +
Für die Wiederverwendung wäre es trivial, ein Modul zu erstellen, das die verschiedenen Flusssteuerungsmuster unterstützt, dh Serien, Parallel, Batch, während, bis usw.