Skip to content

Instantly share code, notes, and snippets.

@utaal
Last active August 29, 2015 14:22
Show Gist options
  • Save utaal/247982d4d103eedc2d9a to your computer and use it in GitHub Desktop.
Save utaal/247982d4d103eedc2d9a to your computer and use it in GitHub Desktop.
promise scheduler (gcanti/fetch-optimizer)
// run with: node --harmony experiment.js
var R = require('ramda');
var PromiseScheduler = (function() {
function PromiseScheduler() {
this.nodes = {};
}
PromiseScheduler.prototype.add = function(id, fetcher, dependencies) {
this.nodes[id] = {
fetcher: fetcher,
dependencies: dependencies
}
return this;
}
// gets maximal elements
PromiseScheduler.prototype.maximal = function() {
var that = this;
return Object.keys(this.nodes).filter(id =>
Object.keys(that.nodes).every(otherId =>
that.nodes[otherId].dependencies.indexOf(id) == -1));
}
// ensures all dependencies of all `nodes` have been started and
// then sets `fetcher` for all `nodes` to be run at completion of
// all its dependencies
//
// we mutate `this.nodes` for memoization (`.promise` is added when a promise has
// been spawned for a fetcher)
PromiseScheduler.prototype._internalSchedule = function(nodes) {
var that = this;
return nodes.map(function(id) {
if (!that.nodes[id].promise) {
that._internalSchedule(that.nodes[id].dependencies);
var dependencyPromises = that.nodes[id].dependencies.map(depId =>
that.nodes[depId].promise);
that.nodes[id].promise = Promise.all(dependencyPromises).then(() =>
that.nodes[id].fetcher());
}
return that.nodes[id].promise;
});
}
PromiseScheduler.prototype.schedule = function() {
return Promise.all(this._internalSchedule(this.maximal()));
}
return PromiseScheduler;
})();
var results = [];
function getFetcher(value, delay) {
return function (res) {
return new Promise(function (resolve) {
console.log((Date.now() - start) + 'ms start ' + value);
setTimeout(function () {
results.push(value);
resolve(value);
console.log((Date.now() - start) + 'ms resolve ' + value);
}, delay);
});
};
}
// f2 f3
// \ / \
// f1 f4
// \ /
// f5 <-- maximal element
const ps = new PromiseScheduler()
.add('f1', getFetcher('f1', 50), ['f2', 'f3'])
.add('f2', getFetcher('f2', 200), [])
.add('f3', getFetcher('f3', 50), [])
.add('f4', getFetcher('f4', 200), ['f3'])
.add('f5', getFetcher('f5', 10), ['f1', 'f4']);
// optimal arrival times (spawining as soon as dependencies are available):
// f2: 200ms
// f3: 50ms
// f1: 250ms = max(f2, f3) + 50ms
// f4: 250ms = 50ms + 200ms
// f5: 260ms = max(f1, f4) + 10ms
//
// with poset chain:
// (f2, f3): 200ms = max(f2, f3)
// (f1, f4): 400ms = 200ms + max(f1, f4)
// (f5): 410ms = 400ms + 10ms
var start = Date.now();
ps.schedule().then(function(res) {
console.log('result ' + results);
console.log('res ' + res);
var end = Date.now();
console.log('done in ' + (end - start) + 'ms');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment