UNPKG

queue.io

Version:

An events based queue iteration JavaScript module

377 lines (289 loc) 10.7 kB
/* Copyright 2014 Lcf.vs Released under the MIT license https://github.com/Lcfvs/Queue.io */ var Queue; Queue = (function (global) { 'use strict'; var main; main = function main(require, exports, module) { var EventEmitter, NEXT, PREV, originalGlobalValue, defer, Queue, parseDirection, parseEmitter, parseEvent, parse, run, Iterator; EventEmitter = require('events').EventEmitter; NEXT = {}; PREV = {}; Object.freeze(NEXT); Object.freeze(PREV); originalGlobalValue = typeof exports === 'object' && exports; defer = (typeof setImmediate === 'function' && setImmediate) || (typeof process === 'object' && process.nextTick) || function (closure) { setTimeout(closure, 0); }; Queue = function Queue(emitter, event) { var queue, sources, handler; queue = this instanceof Queue ? this : Object.create(Queue.prototype); sources = []; handler = { pending: 0, emitter: new EventEmitter(), event: parseEvent(event, emitter), queue: queue, sources: sources, values: [] }; handler.emitter.once('done', queue.emit.bind(queue, 'done')); queue.iterate = function iterate(direction) { var values, iterator; values = handler.values; iterator = Iterator(values, handler.event, queue, direction); if (handler.isTicked && !handler.pending) { defer(values.next); } else { handler.emitter.once('done', values.next); } return iterator; }; queue.append = function append(queue, event, direction) { var source; if (!handler.isTicked || handler.pending) { source = parse(handler, queue, event, direction); sources.push(source); if (sources.length === 1) { source.run(); } } return queue; }; queue.listen = function listen(queue, event, direction) { var source; if (!handler.isTicked || handler.pending) { source = parse(handler, queue, event, direction); source.run(); } return queue; }; queue.intercept = function intercept(callback, event, direction) { if (!handler.isTicked || handler.pending) { handler.pending += 1; return function (error, values) { if (error) { return handler.queue.emit('error', error); } if (values instanceof Queue) { callback.call(handler.queue, values, event, direction); } else if (values instanceof EventEmitter) { callback.call(handler.queue, Queue(values, event), event, direction); } else { callback.call(handler.queue, Queue.from(values), parseDirection(event, direction)); } handler.pending -= 1; }; } }; if (parseEmitter(emitter)) { queue.listen(emitter, event); } defer(function () { handler.isTicked = true; if (!handler.pending) { handler.emitter.emit('done'); } }); return queue; }; Queue.prototype = Object.create(EventEmitter.prototype, { constructor: { value: Queue, writable: true, configurable: true } }); Queue.from = function from(values, event) { var index, length, emitter, eventName, queue; index = 0; length = values.length; emitter = new EventEmitter(); eventName = parseEvent(event); queue = Queue(emitter, eventName); for (; index < length; index += 1) { emitter.emit(eventName, values[index]); } emitter.emit('done'); return queue; }; parseDirection = function parseDirection(direction, extra) { return direction === NEXT || direction === PREV ? direction : extra === NEXT || extra === PREV ? extra : NEXT; }; parseEmitter = function parseEmitter(emitter) { if (emitter instanceof EventEmitter) { return emitter; } }; parseEvent = function parseEvent(event, extra) { return typeof event === 'string' ? event : typeof extra === 'string' ? extra : 'value'; }; parse = function parse(handler, emitter, event, direction) { handler.pending += 1; return { direction: parseDirection(direction, event), emitter: parseEmitter(emitter), event: parseEvent(event), handler: handler, run: run }; }; run = function run() { var source, emitter, event, handler, queue, sources, values, onvalue; source = this; emitter = source.emitter; event = source.event; handler = source.handler; queue = handler.queue; sources = handler.sources; values = handler.values; if (emitter instanceof Queue) { emitter = emitter.iterate(source.direction); } onvalue = function onvalue(value, next) { values.push(value); if (next) { next(); } }; emitter.on(event, onvalue); emitter.once('done', function () { var sources, next; emitter.removeListener(event, onvalue); handler.pending -= 1; sources = handler.sources; if (sources[0] === source) { sources.shift(); next = handler.sources[0]; if (next) { next.run(); } } defer(function () { if (handler.isTicked && !handler.pending && !handler.sources.length) { handler.emitter.emit('done'); } }); }); emitter.once('error', queue.emit.bind(queue, 'error')); }; Iterator = function Iterator(values, event, queue, direction) { var index, iterator, getNext, iterationValues; index = 0; iterator = new EventEmitter(); getNext = function getNext() { var next, isReached; next = function next() { var args; if (!iterationValues) { iterationValues = values.slice(0); if (direction === PREV) { iterationValues.reverse(); } } if (!isReached) { args = Array.prototype.slice.call(arguments, 0); defer(function () { var value; if (index >= iterationValues.length) { iterator.emit('done', queue); } else { value = iterationValues[index]; if (typeof value === 'function') { value = (function() { return value; }()); } args.unshift(event, value, getNext(), queue); iterator.emit.apply(iterator, args); } index += 1; }); isReached = true; } }; return next; }; values.next = getNext(); return iterator; }; Object.defineProperty(Queue, 'NEXT', { value: NEXT, enumerable: true }); Object.defineProperty(Queue, 'PREV', { value: PREV, enumerable: true }); Queue.noConflict = function noConflict() { module.exports = originalGlobalValue; return Queue; }; return Queue; }; if (typeof define === 'function' && define.amd) { define(main); } else if (typeof module === 'object' && module.exports) { return module.exports = main(require); } return main(function () { var EventEmitter; EventEmitter = global.events ? global.events.EventEmitter : global.EventEmitter; if (!EventEmitter) { throw new Error('Unable to find EventEmitter'); } return { EventEmitter: EventEmitter }; }); }(this));