@spalger/kibana
Version:
Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elastic
186 lines (162 loc) • 3.83 kB
JavaScript
define(function (require) {
return function LooperFactory($timeout, Notifier, Promise) {
var _ = require('lodash');
var notify = new Notifier();
function Looper(ms, fn) {
this._fn = fn;
this._ms = ms === void 0 ? 1500 : ms;
this._timer = null;
this._started = false;
this._loopTheLoop = _.bind(this._loopTheLoop, this);
}
/**
* Set the number of milliseconds between
* each loop
*
* @param {integer} ms
* @chainable
*/
Looper.prototype.ms = function (ms) {
this._ms = _.parseInt(ms) || 0;
if (!this._started) return;
if (this._ms) {
this.start(false);
} else {
this._unScheduleLoop();
}
return this;
};
/**
* Cancels the current looper while keeping internal
* state as started
*
* @chainable
*/
Looper.prototype.pause = function () {
this._unScheduleLoop();
return this;
};
/**
* Start the looping madness
*
* @chainable
*/
Looper.prototype.start = function (loopOver) {
if (loopOver == null) loopOver = true;
if (!this._started) {
this._started = true;
} else {
this._unScheduleLoop();
}
if (loopOver) {
this._loopTheLoop();
} else {
this._scheduleLoop();
}
return this;
};
/**
* ...
*
* @chainable
*/
Looper.prototype.stop = function () {
this._unScheduleLoop();
this._started = false;
return this;
};
/**
* Restart the looper only if it is already started.
* Called automatically when ms is changed
*
* @chainable
*/
Looper.prototype.restart = function () {
this.start(false);
return this;
};
/**
* Is the looper currently started/running/scheduled/going to execute
*
* @return {boolean}
*/
Looper.prototype.started = function () {
return !!this._started;
};
/**
* Returns the current loop interval
*
* @return {number}
*/
Looper.prototype.loopInterval = function () {
return this._ms;
};
/**
* Called when the loop is executed before the previous
* run has completed.
*
* @override
* @return {undefined}
*/
Looper.prototype.onHastyLoop = function () {
// override this in subclasses
};
/**
* Wraps this._fn so that this._fn can be changed
* without rescheduling and schedules
* the next itteration
*
* @private
* @return {undefined}
*/
Looper.prototype._loopTheLoop = function () {
var self = this;
if (self.active) {
self.onHastyLoop();
return;
}
self.active = Promise
.try(this._fn)
.then(function () {
self._scheduleLoop();
})
.catch(function (err) {
self.stop();
notify.fatal(err);
})
.finally(function () {
self.active = null;
});
};
/**
* Schedule the next itteration of the loop
*
* @private
* @return {number} - the timer promise
*/
Looper.prototype._scheduleLoop = function () {
this._unScheduleLoop();
this._timer = this._ms ? $timeout(this._loopTheLoop, this._ms) : null;
return this._timer;
};
/**
* Cancel the next itteration of the loop
*
* @private
* @return {number} - the timer promise
*/
Looper.prototype._unScheduleLoop = function () {
if (this._timer) {
$timeout.cancel(this._timer);
this._timer = null;
}
};
/**
* execute the this._fn, and restart the timer
*/
Looper.prototype.run = function () {
this.start();
};
return Looper;
};
});