type-enforcer
Version:
Type enforcement library for javascript
163 lines (148 loc) • 3.18 kB
JavaScript
import { forOwn } from 'lodash';
import isFunc from '../checks/isFunc';
const CALLBACKS = Symbol();
const CURRENT_ID = Symbol();
const TOTAL = Symbol();
const IS_BUSY = Symbol();
/**
* A simple queue for callbacks that allows for adding, removing, and triggering all or specific callbacks
*
* ## Usage
* ``` javascript
* import { Queue } from 'type-enforcer';
* ```
*
* @class Queue
*/
export default class Queue {
constructor() {
this[CURRENT_ID] = 0;
this[IS_BUSY] = false;
this.discardAll();
}
/**
* Add a callback to the queue.
*
* @memberof Queue
* @instance
*
* @arg {Function} callback - Callback function.
* @arg {Object} data - Any arbitrary data. Returned when the callback is discarded.
*
* @returns {Number} A unique ID for this callback.
*/
add(callback, data) {
if (isFunc(callback)) {
const newID = (++this[CURRENT_ID] + '');
this[CALLBACKS][newID] = {
func: callback,
data: data
};
this[TOTAL]++;
return newID;
}
}
/**
* Remove a specific callback from the queue.
*
* @memberof Queue
* @instance
*
* @arg {Number} ID - The ID returned by Queue.add().
*
* @returns {Object} The data object added with this callback
*/
discard(ID) {
let data;
if (ID && this[CALLBACKS][ID]) {
data = this[CALLBACKS][ID].data;
delete this[CALLBACKS][ID];
this[TOTAL]--;
}
return data;
}
/**
* Remove ALL callbacks from the queue.
*
* @memberof Queue
* @instance
*/
discardAll() {
this[CALLBACKS] = {};
this[TOTAL] = 0;
}
/**
* Triggers one or all callbacks.
*
* @memberof Queue
* @instance
*
* @arg {Number} [ID] - To trigger only a specific callback, provide the ID returned by Queue.add().
* Otherwise all callbacks are called.
* @arg {Array} [extraArguments] - Array of arguments to apply to each callback.
* @arg {Array} [context]
*
* @returns {this}
*/
trigger(ID, extraArguments, context) {
this[IS_BUSY] = true;
if (ID) {
if (this[CALLBACKS][ID]) {
this[CALLBACKS][ID].func.apply(context, extraArguments);
}
}
else {
forOwn(this[CALLBACKS], (callback) => {
if (callback) {
callback.func.apply(context, extraArguments);
}
});
}
this[IS_BUSY] = false;
return this;
}
/**
* Triggers the first callback and removes it from the queue.
*
* @memberof Queue
* @instance
*
* @arg {Array} [extraArguments] - Array of arguments to apply to each callback.
* @arg {Array} [context] - "this" applied to the callback
*
* @returns {this}
*/
triggerFirst(extraArguments, context) {
const self = this;
this[IS_BUSY] = true;
forOwn(this[CALLBACKS], (callback, ID) => {
callback.func.apply(context, extraArguments);
self.discard(ID);
return false;
});
this[IS_BUSY] = false;
return this;
}
/**
* The total number of current callbacks in this queue.
*
* @memberof Queue
* @instance
*
* @returns {number}
*/
get length() {
return this[TOTAL];
}
/**
* See if this queue is currently executing callbacks.
*
* @memberof Queue
* @instance
*
* @returns {boolean}
*/
get isBusy() {
return this[IS_BUSY];
}
}