Browse Source

Created a Queue

v3_develop
jos 10 years ago
parent
commit
f9ca7e5183
2 changed files with 262 additions and 0 deletions
  1. +124
    -0
      lib/Queue.js
  2. +138
    -0
      test/Queue.test.js

+ 124
- 0
lib/Queue.js View File

@ -0,0 +1,124 @@
/**
* A queue
* @param {Object} options
* Available options:
* - delay: number When a number, the queue will be flushed
* automatically after an inactivity of this delay
* in milliseconds.
* When false (default), the queue is not flushed
* - max: number When the queue exceeds the given maximum number
* of entries, the queue is flushed automatically.
* Default value of max is Infinity.
* @constructor
*/
function Queue(options) {
// options
this.delay = options && typeof options.delay === 'number' ? options.delay : false;
this.max = options && typeof options.max === 'number' ? options.max : Infinity;
// properties
this._queue = [];
this._timeout = null;
}
/**
* Extend an object with queuing functionality.
* The object will be extended with a function flush, and the methods provided
* in options.replace will be replaced with queued ones.
* @param {Object} object
* @param {Object} options
* Available options:
* - replace: Array.<string>
* A list with method names of the methods
* on the object to be replaced with queued ones.
* - delay: number When a number, the queue will be flushed
* automatically after an inactivity of this delay
* in milliseconds.
* When false (default), the queue is not flushed
* - max: number When the queue exceeds the given maximum number
* of entries, the queue is flushed automatically.
* Default value of max is Infinity.
*/
Queue.extend = function (object, options) {
var queue = new Queue(options);
if (object.flush !== undefined) {
throw new Error('Target object already has a property flush');
}
object.flush = function () {
queue.flush();
};
if (options && options.replace) {
for (var i = 0; i < options.replace.length; i++) {
queue.replace(object, options.replace[i]);
}
}
};
/**
* Replace a method on an object with a queued version
* @param {Object} object Object having the method
* @param {string} method The method name
*/
Queue.prototype.replace = function(object, method) {
var me = this;
var original = object[method];
if (!original) {
throw new Error('Method ' + method + ' undefined');
}
object[method] = function () {
// create an Array with the arguments
var args = [];
for (var i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
}
// add this call to the queue
me.queue({
args: args,
fn: original,
context: this
});
};
};
/**
* Queue a call
* @param {function | {fn: function, args: Array} | {fn: function, args: Array, context: Object}} entry
*/
Queue.prototype.queue = function(entry) {
if (typeof entry === 'function') {
this._queue.push({fn: entry});
}
else {
this._queue.push(entry);
}
// flush when the maximum is exceeded.
if (this._queue.length > this.max) {
this.flush();
}
// flush after a period of inactivity when a delay is configured
if (typeof this.delay === 'number') {
var me = this;
clearTimeout(this._timeout);
this._timeout = setTimeout(function () {
me.flush();
}, this.delay);
}
};
/**
* Flush all queued calls
*/
Queue.prototype.flush = function () {
while (this._queue.length > 0) {
var entry = this._queue.shift();
entry.fn.apply(entry.context || entry.fn, entry.args || []);
}
};
module.exports = Queue;

+ 138
- 0
test/Queue.test.js View File

@ -0,0 +1,138 @@
var assert = require('assert');
var Queue = require('../lib/Queue');
describe('Queue', function () {
it('queue, queue actions', function () {
var queue = new Queue();
var count = 0;
function inc() {
count++;
}
queue.queue(inc);
assert.equal(count, 0);
queue.flush();
assert.equal(count, 1);
});
it('queue, queue actions with a delay', function (done) {
var queue = new Queue({delay: 25});
var count = 0;
function inc() {
count++;
}
queue.queue(inc);
assert.equal(count, 0);
setTimeout(function () {
assert.equal(count, 1);
done();
}, 50);
});
it('queue, queue multiple actions with a delay', function (done) {
var queue = new Queue({delay: 100});
var count = 0;
function inc() {
count++;
}
queue.queue(inc);
assert.equal(count, 0);
setTimeout(function () {
queue.queue(inc);
assert.equal(count, 0);
// flush should now occur after 100 ms from now, lets test after 75 and 125 ms
setTimeout(function () {
assert.equal(count, 0);
setTimeout(function () {
assert.equal(count, 2);
done();
}, 50);
}, 75);
}, 50);
});
it('queue actions with args', function () {
var queue = new Queue();
var count = 0;
function add(value) {
count += value;
}
queue.queue({fn: add, args: [2]});
assert.equal(count, 0);
queue.flush();
assert.equal(count, 2);
});
it('queue actions with args and context', function () {
var queue = new Queue();
var obj = {
count: 0,
add: function (value) {
this.count += value;
}
};
queue.queue({context: obj, fn: obj.add, args: [2]});
assert.equal(obj.count, 0);
queue.flush();
assert.equal(obj.count, 2);
});
it('replace functions on an object', function () {
var queue = new Queue();
var obj = {
count: 0,
add: function (value) {
this.count += value;
}
};
queue.replace(obj, 'add');
obj.add(3);
assert.equal(obj.count, 0);
queue.flush();
assert.equal(obj.count, 3);
});
it('extend an object', function () {
var obj = {
count: 0,
add: function (value) {
this.count += value;
},
subtract: function (value) {
this.count -= value;
}
};
Queue.extend(obj, {replace: ['add', 'subtract']});
obj.add(3);
obj.subtract(1);
assert.equal(obj.count, 0);
obj.flush();
assert.equal(obj.count, 2);
});
});

Loading…
Cancel
Save