JavaScript Promise Dependency Handling
This is an example how you can asynchronously traverse a directed acyclic graph, without evaluating the individual nodes multiple times. Be careful, cycles in the dependency graph cause a deadlock in this implementation.
function Model(name, requires) {
this.name = name;
this.requires = requires;
};
// this function is available as `Promise.delay` when using bluebird
function delay(x, v) {
return new Promise(resolve => {
setTimeout(() => { resolve(v); }, x);
});
}
Model.prototype.process = function () {
console.log('started processing: ', this.name);
return delay(Math.random() * 100 + 100).then(() => {
console.log('finished processing: ', this.name);
});
};
function Processor(models) {
this.processMap = {};
this.models = models;
models.forEach(m => {
this.processMap[m.name] = {
promise: null,
model: m
};
});
}
Processor.prototype.processDependencies = function(model) {
return Promise.all(model.requires.map(r => this.processByName(r)));
};
Processor.prototype.process = function(model) {
const process = this.processMap[model.name];
if (!process.promise) {
process.promise = this.processDependencies(model)
.then(() => model.process());
}
return process.promise;
};
Processor.prototype.processByName = function(modelName) {
return this.process(this.processMap[modelName].model);
};
function test() {
const models = [
new Model('bottom', []),
new Model('mid a', ['bottom']),
new Model('mid b', ['bottom']),
new Model('top', ['mid a', 'mid b'])
];
const processor = new Processor(models);
Promise.all(
models.map(m => processor.process(m))
).then(allResults => {
console.log("All process finished");
}, e => {
console.error(e);
});
}
test();