pcottle.learnGitBranching/src/async.js
2012-08-15 13:05:43 -07:00

175 lines
3.5 KiB
JavaScript

/**
* Util classes
*/
function CommandQueue() {
this.commands = [];
this.consumeTimeout = null;
this.initialDelay = 400;
}
CommandQueue.prototype.add = function(command) {
this.commands.push(command);
this.touchTimer();
};
CommandQueue.prototype.touchTimer = function() {
if (this.consumeTimeout) {
return;
}
this.consumeTimeout = setTimeout(_.bind(function() {
this.next();
}, this), this.initialDelay);
};
CommandQueue.prototype.reset = function() {
this.consumeTimeout = null;
};
CommandQueue.prototype.next = function() {
if (this.commands.length == 0) {
this.reset();
return;
}
// execute the top command by passing it into the engine
var toExecute = this.commands.shift(0);
var callback = _.bind(function() {
this.next();
}, this);
gitEngine.execute(toExecute, callback);
};
/******************
* Planning:
here is the major flow:
someone types in a command ->
make a new command object. if error, give immediate feedback, dont append to queue
if not error ->
append command object to queue
Command Queue ->
consume commands at a certain rate (either instantly if just added, or with an interval
Execute command -> (usually a git engine thing)
Wait for git engine command to finish
when done, execute next command (if more)
so two levels of Async-ness:
command queue slowly consumes commands
GitEngine executes commands, which will have async bits to them (such as popping off commits for a
rebase)
*/
function Scheduler(closures, options) {
if (!closures || !closures.length) {
throw new Error('invalid params');
}
this.closures = closures;
this.options = options || {};
this.interval = this.options.interval || 400;
this.done = false;
this.timeOut = null;
this.index = 0;
}
Scheduler.prototype.start = function() {
// set the first interval
this.index = 0;
this.done = false;
this.setNext();
};
Scheduler.prototype.setNext = function(interval) {
this.timeOut = setTimeout(_.bind(function() {
this.step();
}, this),
interval || this.interval);
};
Scheduler.prototype.finish = function() {
this.done = true;
clearTimeout(this.timeOut);
this.timeOut = null;
if (this.options.callback) {
this.options.callback();
}
};
Scheduler.prototype.step = function() {
if (this.done) {
return;
}
var results = this.closures[this.index]() || {};
this.index++;
if (results.done || this.index >= this.closures.length) {
this.finish();
return;
}
this.setNext(results.interval);
};
/**
* class Breather
*/
function Breather(closure, baseline, delta, period, wait) {
this.delta = delta;
this.baseline = baseline;
this.closure = closure;
this.t = 0;
this.interval = 1/40 * 1000; // 40fps
var period_in_seconds = period || time.breathePeriod;
this.period = 2 * Math.PI * 1000 * period_in_seconds;
this.interpolationFunction = TWEEN.Easing.Cubic.EaseInOut;
if (wait) {
setTimeout(_.bind(function() {
this.start();
}, this), wait);
} else {
this.start();
}
}
Breather.prototype.start = function() {
this.t = 0;
this.next();
};
Breather.prototype.next = function() {
this.timeout = setTimeout(
_.bind(function() {
this.breathe();
}, this),
this.interval);
};
Breather.prototype.stop = function() {
clearTimeout(this.timeout);
};
Breather.prototype.breathe = function() {
this.t += this.interval;
var value = Math.sin(this.t / this.period) * this.delta + this.baseline;
this.closure(value);
this.next();
};